我有一个基本的sql选择问题,人们多年来给了我不同的答案。假设我有两个表,每个表有40多个列,可能会有十几行,我正在使用SqlServer2005。
在加入这些表时,在where子句中,如果我有
之类的东西select * from t1, t2
where t1.UserID = 5
and t1.SomeID = t2.SomeOtherID
有些人说你应该在前面有“t1.UserID = 5”,而不是在“t1.SomeID = t2.SomeOtherID”之后,它会提升选择性能。虽然其他人说没关系。
答案是什么?
此外,如果我使用ADO.NET实体框架来实现我的DAL,那么对具有超过40列并执行CRUD操作的表进行建模会对它产生性能问题吗?
谢谢,
雷
答案 0 :(得分:4)
通常,对于数据库优化,您应首先编写概念上正确的SQL,然后在分析显示必要时调整性能。在进行内连接时,最好使用SQL-92,明确的INNER JOIN而不是笛卡尔积。所以我首先编写SQL,如下所示:
SELECT *
FROM t1
INNER JOIN t2
ON t1.SomeID = t2.SomeOtherID
WHERE
t1.UserID = 5
在INNER JOIN的ON部分中的t1.SomeID = t2.SomeOtherID,因为它表示两个表之间的关系。进入WHERE子句的UserID,因为它是一个限制结果集的过滤器。以这种方式编写SQL会为数据库优化器提供更多信息,因为它表达了您对连接与过滤的意图。
现在,如果您在实际数据库中使用此语法无法获得可接受的性能,那么请随意尝试移动位。但就像我说的那样,从概念上正确的东西开始。
关于问题的第二部分,最明显的性能含义是,当您选择实体集合时,实体框架需要为其实现的实体带回所有属性。因此,如果您有40列,那么如果您将它们实现为实体,那么您将通过网络将数据拉回来。但是,可以编写LINQ查询,这些查询返回仅包含所需列的匿名类型。但是,要执行完整的CRUD,您需要返回实体。
答案 1 :(得分:2)
人们对此的看法会随着时间而改变,因为RDBMS查询优化随着时间的推移而发展,不同的RDBMS将有不同的方法。我不能代表那里的每一个系统,但是在2008年这不太可能会产生任何影响。 YMMV如果您只对特定系统感兴趣。
我可以告诉你,对于任何最新版本的Oracle,它没有任何区别。
答案 2 :(得分:1)
我知道这个答案有点陈词滥调,但我建议写基准。打开一个控制台应用程序并自己测试它。运行查询几百次,看看每种方式需要多长时间。
在SQL查询性能和优化方面存在很多迷信。有些人认为事情更快但他们实际上没有检查他们的事实。此外,EF或LinqToSql与DB一起工作和交互的方式可能会引入SQL中不明显的性能差异。
如果您正在优化代码,您可能还想使用像RedGate ANTS这样的分析器。它不是免费的,但它可以帮助您找到代码中的瓶颈。然后,您可以在代码中找到更容易优化的位置。并不总是您的数据库会降低您的应用程序速度。或者有时你正在执行一个快速查询,但是当你实际上可以缓存结果时,它会执行数千次。
答案 3 :(得分:0)
首先,使用显式JOIN语法而不是笛卡尔积来构造查询。对于任何现代优化器来说,它可能在性能方面没有任何差别,但它确实使得有关JOIN如何为程序员更容易访问的信息。
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
这将给我们所有按名称排序的玩家,他们在游戏中占用的碎片数量超过了游戏中所有其他游戏玩家以及游戏的日期。将这两个条件放在JOIN中可能也不会影响性能,因为优化器很可能无论如何都要将过滤作为JOIN的一部分。但它确实对LEFT JOIN很重要。让我们说我们正在寻找本周前十名球员赢得了多少场比赛。由于其中有些人可能从未有过这一次,我们需要LEFT 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
嗯,不太好。如果玩家没有玩过任何游戏,JOIN将返回玩家玩的每个游戏的记录,或玩家数据和NULL游戏数据。根据优化者的决定,这些结果将在JOIN期间或之后进行过滤,具体取决于frag标准。这将消除所有不符合frag标准的记录。因此,对于那些从未有如此壮观的胜利的球员,将没有记录。有效地创建INNER JOIN ....失败。
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中,查询将正常运行,返回本周前十名中所有玩家的记录,无论他们是否已经实现粉饰。
毕竟,简短的回答是:
对于INNER JOIN情况,它可能不会在您放置条件时产生性能差异。如果您将连接和过滤条件分开,则查询更具可读性。在错误的地方得到一个条件会严重影响LEFT JOIN的结果。