Performance 数据库和EF性能问题?

Performance 数据库和EF性能问题?,performance,entity-framework,database-design,select,Performance,Entity Framework,Database Design,Select,我有一个基本的sql选择问题,多年来人们给了我不同的答案。假设我设计了两个表,每个表都有40多列,可能包含10行和数千行,我使用的是SqlServer2005 在连接这些表时,在where子句中 select * from t1, t2 where t1.UserID = 5 and t1.SomeID = t2.SomeOtherID 有些人说,您应该在前面设置常量“t1.UserID=5”,而不是在“t1.SomeID=t2.SomeOtherID”之后,这样可以提高select性能。而

我有一个基本的sql选择问题,多年来人们给了我不同的答案。假设我设计了两个表,每个表都有40多列,可能包含10行和数千行,我使用的是SqlServer2005

在连接这些表时,在where子句中

select * from t1, t2
where t1.UserID = 5 
and t1.SomeID = t2.SomeOtherID
有些人说,您应该在前面设置常量“t1.UserID=5”,而不是在“t1.SomeID=t2.SomeOtherID”之后,这样可以提高select性能。而其他人则认为这无关紧要

正确答案是什么

另外,如果我使用ADO.NET实体框架来实现DAL,那么对超过40列的表进行建模和执行CRUD操作是否会成为性能问题

谢谢,


Ray。

一般来说,对于数据库优化,您应该首先编写概念正确的SQL,然后在分析显示有必要时调整性能。在进行内部联接时,最好使用SQL-92,即显式内部联接,而不是笛卡尔乘积。因此,我将首先编写SQL,如下所示:

SELECT * 
FROM t1
  INNER JOIN t2
    ON t1.SomeID = t2.SomeOtherID
WHERE
  t1.UserID = 5 
t1.SomeID=t2.SomeOtherID,它位于内部联接的ON部分,因为它表示两个表之间的关系。WHERE子句中的用户ID,因为它是限制结果集的筛选器。以这种方式编写SQL将为数据库优化器提供更多信息,因为它表达了您对连接和筛选的意图

现在,如果在现实世界的数据库中使用这种语法无法获得可接受的性能,那么请随意尝试移动位。但就像我说的,从概念上正确的东西开始


关于问题的第二部分,最明显的性能含义是,当您选择一个实体集合时,实体框架需要返回它正在具体化的实体的所有属性。因此,如果您有40列,那么如果您将它们具体化为实体,您将通过连接将这些数据拉回来。但是,可以编写LINQ查询,返回只包含所需列的匿名类型。然而,要完成完整的CRUD,您需要返回实体。

我知道这个答案有点陈腐,但我建议编写基准测试。制作一个控制台应用程序,自己测试一下。运行查询几百次,看看每种方式需要多长时间

在SQL查询性能和优化方面存在很多迷信。有些人认为这样做更快,但实际上他们并不检查自己的事实。此外,EF或LinqToSql的工作方式以及与DB的交互方式可能会引入SQL中不明显的性能差异


如果您正在优化代码,您可能还希望使用诸如RedGate ANTS之类的探查器。它不是免费的,但它可以帮助您在代码中找到瓶颈。然后,您可以在代码中找到更容易优化的位置。不是你的数据库总是让你的应用程序慢下来。或者,有时您正在执行一个快速查询,但在实际缓存结果时却要执行无数次。

人们对此的看法会随着时间的推移而改变,因为RDBMS查询优化随着时间的推移而发展,不同的RDBMS会有不同的方法。我不能为每个系统说话,但在2008年,这真的不太可能产生任何影响。YMMV,如果您只对特定系统感兴趣


我可以告诉您,对于任何最新版本的Oracle来说,这都没有什么区别。

首先,使用显式连接语法而不是笛卡尔乘积构造查询。对于任何现代的优化人员来说,它可能不会在性能方面产生任何影响,但它确实让程序员更容易获得关于连接如何工作的信息


SELECT Player.Name, Game.Date
 FROM Player
  INNER JOIN Game ON Game.WinnerPlayerID = Player.PlayerID
 WHERE Game.WinnerFrags > Game.TotalFrags/2
 ORDER BY Player.Name
这将给我们按名字排序的所有玩家,他们在游戏中比游戏中所有其他玩家的总和都多,以及游戏的日期。将这两个条件都放在连接中可能也不会影响性能,因为优化者可能会将过滤作为连接的一部分。不过,对于左连接来说,它确实开始起作用了。假设我们正在寻找本周前十名球员以上述差距赢得过多少场比赛。因为有可能他们中的一些人从来没有这样壮观过,所以我们需要左键连接


SELECT Player.WeekRank, Player.Name, COUNT(Game.*) AS WhitewashCount
 FROM Player
  LEFT JOIN Game ON Game.WinnerPlayerID = Player.PlayerID
 WHERE Player.WeekRank >= 10
  AND Game.WinnerFrags > Game.TotalFrags/2
 GROUP BY Player.WeekRank, Player.Name
 ORDER BY Player.WeekRank
嗯,不完全是。加入将返回玩家玩过的每一场游戏的记录,如果玩家没有玩过游戏,则返回玩家数据和空游戏数据。根据frag标准,这些结果将在连接期间或之后根据优化人员的决定进行过滤。这将消除所有不符合frag标准的记录。因此,对于从未获得如此壮观胜利的球员,将不会有任何记录可供分组。有效地创建内部连接。。。。失败


SELECT Player.WeekRank, Player.Name, COUNT(Game.*) AS WhitewashCount
 FROM Player
  LEFT JOIN Game ON Game.WinnerPlayerID = Player.PlayerID
   AND Game.WinnerFrags > Game.TotalFrags/2
 WHERE Player.WeekRank >= 10
 GROUP BY Player.WeekRank, Player.Name
 ORDER BY Player.WeekRank
一旦我们将frag标准移动到JOIN中,查询将正确运行,返回本周前十名中所有玩家的记录,无论他们是否实现了粉饰

在所有这些之后,简短的回答是:

对于内部连接情况,在设置条件的地方可能不会对性能产生影响。但是,如果将连接条件和筛选条件分开,查询的可读性会更高。在错误的位置获取条件会严重破坏左联接的结果


SELECT Player.WeekRank, Player.Name, COUNT(Game.*) AS WhitewashCount
 FROM Player
  LEFT JOIN Game ON Game.WinnerPlayerID = Player.PlayerID
 WHERE Player.WeekRank >= 10
  AND Game.WinnerFrags > Game.TotalFrags/2
 GROUP BY Player.WeekRank, Player.Name
 ORDER BY Player.WeekRank