2008-12-17 60 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情況下,它可能不會使你放置的條件的性能差異。如果您分開加入和過濾條件,查詢更具可讀性。在錯誤的地方獲取條件可能會嚴重影響左連接的結果。