2008-12-17 61 views
0

我有一个基本的SQL选择问题,人们给了我多年来不同的答案。假设我有几个表,每个表的设计都有40多列,并且可能会存放10行和数千行,我正在使用SqlServer2005。数据库和EF性能问题?

在加入这些表,在where子句中,如果我有喜欢的东西

select * from t1, t2 
where t1.UserID = 5 
and t1.SomeID = t2.SomeOtherID 

有人说,你应该alwasys有固定的“t1.UserID = 5”前面,而不是“t1之后。 SomeID = t2.SomeOtherID“,它提高了选择性能。而其他人则说这没有关系。

什么是正确答案?另外,如果我使用ADO.NET Entity Framework来实现我的DAL,那么建模超过40列并执行CRUD操作的表会对性能产生影响吗?

谢谢,

雷。

回答

4

一般来说,通过数据库优化,您应该先编写概念上正确的SQL,然后在性能分析显示它是必要时调整性能。在进行内部连接时,最好使用SQL-92,明确的INNER JOIN比笛卡尔产品。所以,我开始写你的SQL如下:

SELECT * 
FROM t1 
    INNER JOIN t2 
    ON t1.SomeID = t2.SomeOtherID 
WHERE 
    t1.UserID = 5 

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

现在,如果您在现实世界的数据库中无法使用此语法获得可接受的性能,请随时尝试移​​动位。但就像我说的,从概念上正确的事情开始。

关于您的问题的第二部分,最明显的性能影响是,当您选择实体集合时,实体框架需要为实体实体带回所有属性。所以,如果你有40列,那么你将通过电线将这些数据回收,如果你将它们实现为实体。但是,可以编写返回仅包含所需列的匿名类型的LINQ查询。但是,要执行完整的CRUD,您需要返回实体。

1

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

当谈到SQL查询性能和优化时,存在很多迷信。有些人认为事情更快,但实际上并没有检查他们的事实。此外,EF或LinqToSql的工作方式和与数据库交互的方式可能会引入SQL中不明显的性能差异。

如果您正在优化代码,您可能还想使用像RedGate ANTS这样的分析器。它不是免费的,但它可以帮助您找到代码中的瓶颈。然后,您可以在代码中找到更容易优化的地方。这并不总是你的数据库放慢你的应用程序。或者有时你正在执行一个快速查询,但是当你实际上可以缓存结果时,执行一次快速查询。

2

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

我可以告诉你,对于任何最新版本的Oracle,它都没有区别。

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 

这将给我们按名称排序的所有球员谁承担更多的frag在一场比赛中比在游戏放在一起的所有其他球员,而比赛的日期。将两个条件都放在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期间或之后得到过滤,具体取决于优化程序的决定。这将消除所有不符合分段标准的记录。所以对于从未有如此壮观胜利的球员来说,将没有记录。有效地创建一个INNER JOIN .... FAIL。


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 

一旦我们把断枝标准为JOIN查询将正确的行为,返回记录在本周十大所有玩家,不论他们是否已经取得了粉饰。

所有这一切后,简短的回答是:

对于INNER JOIN情况下,它可能不会使你放置的条件的性能差异。如果您分开加入和过滤条件,查询更具可读性。在错误的地方获取条件可能会严重影响左连接的结果。