2011-05-02 64 views
14

我已經搜索了四周的stackoverflow,但每個人都要求優化他們已經完成的查詢。如何編寫最佳SQL查詢

我想知道,做什麼的基本內容,創建查詢時要避免什麼。

例如,這是一個已知的事實,寫作SELECT * FROM是一件要避免的事情,因爲sql引擎必須做一個「隱形」查詢來知道應該顯示哪些列。

也知道between @min_number AND @max_numberId >= @min_number AND Id <= @max_number更好,但我不記得原因。這可能是因爲之間是由引擎控制在較低級別的句子,並創建迭代來顯示regs以某種方式「處理」。但我不確定。

有人可以驗證這些,並列出最常見的該做什麼,該怎麼避免

+0

我會與'select * from'的情況爭論。取決於特定的SQL編譯器(每個數據庫引擎如何編譯它接收的某種字節碼的SQL)的工作方式,它可能需要或可能不需要額外的工作。你沒有指定任何特定的數據庫。 – 2011-05-02 13:38:27

+1

'between'是否比'<' and '>'更好取決於特定的SQL優化器。有了它,它總能看到它是一個範圍,但它可能會或可能不會被使用,而'<' and '>'它可能會錯過它的範圍。 – 2011-05-02 13:40:12

+1

優秀的問題 – HLGEM 2011-05-02 14:00:08

回答

11

我的目錄是SQL Server特定(我敢肯定,很多更多):

使用優化搜索where子句 - 這意味着沒有特別的功能標UDF在where子句中

WHERE NOT EXISTS往往是比左連接更快的選擇,其中id是null結構,當您查找與第二個表不匹配的行時。

相關的子查詢往往逐行運行,速度非常慢。

調用其他視圖的視圖不能被編入索引,並且變得非常慢,特別是如果您在大型表上獲得多個級別。

由於至少有一列發送兩次,這是浪費服務器和數據庫及網絡資源,所以選擇*時應特別避免。

光標通常可以用速度更快的基於集合的邏輯來代替 當您以正確的方式存儲數據時,可以避免很多即時轉換。

更新時,請確保添加了where子句,以便不更新新值和舊值相同的行。這可能是更新10,000,000行和更新15樣品之間的differnce(TSQL更新結構,如果使用其他數據庫,你可能要查找正確的語法,但它應該給你的想法。):

Update t 
set field1 = t2.field2 
from table1 t 
join table2 t2 on t.tid = t2.tid 
Where t.field1 <> t2.field2 

或者

Update t 
set field1 = @variable 
from table1 t 
Where t.field1 <> @variable 

如果你經常使用的一個字段的功能,你可能無法正確保存它(或你應該有一個持久計算領域,並做改造每次選擇列的時間只有一次沒有。)

你最好b et是爲你的數據庫選擇一個好的性能調優書(最適合數據庫的最好的),並閱讀有關編寫查詢的章節。

+0

Thanks @HLGEM是SQL Server的特定原因,因爲這不會發生在其他引擎上,或者因爲您在SQL Server上工作,因此只能說出您的知識在那個編譯器中? – apacay 2011-05-02 14:39:15

+0

性能調整是數據庫特定的。我懷疑其中的一些在其他數據庫引擎上也是一樣的,但不知道,因爲我只用SQl Server深入工作。這就是爲什麼閱讀關於您所使用的特定dbs的性能調優非常重要的原因。而且這也是爲什麼很多沒有綁定到一個數據庫的COTS程序在性能上非常糟糕的原因。 – HLGEM 2011-05-02 14:50:55

+0

我和你一樣。我幾乎完全與MS SQL Srv一起工作。社區wiki可以寫在這裏嗎?我會編譯你所有人都說過的話。 – apacay 2011-05-03 18:43:48

4

在您的WHERE子句中,避免使用列作爲函數的輸入,因爲這會導致全表掃描而不能使用索引。某些平臺上的查詢優化器比其他平臺做得更好,但通常更安全。舉例來說,如果你從過去的30天尋找記錄,做對你是比較反對,並不反對你的列中的日期數據操作:

BAD

WHERE DATEADD(DAY, 30, [RecordDate]) > GETDATE() 

這可能導致全表掃描(取決於您的平臺的查詢優化器),即使[RecordDate]已編入索引,因爲必須對DATEADD(DAY, 30, [RecordDate])進行評估,以便將其與GETDATE()進行比較。如果您將其更改爲:

更好

WHERE [RecordDate] > DATEADD(DAY, -30, GETDATE()) 

這將現在總是能夠在[RecordDate]使用索引不管查詢計劃優化器是多麼好你的平臺上,因爲DATEADD(DAY, -30, GETDATE())被計算一次然後可以用作索引中的查找。同樣的原則也適用於使用CASE聲明,UDF的,等

+0

始終是好的 – gbn 2011-05-02 14:25:59

+0

同樣適用於select語句 – Magnus 2011-05-02 14:27:29

6
  • Views are macros,不是魔術
  • 存在和不存在的列上工作最通常
  • 功能(見喬爾C'S答案)
  • 謹防implicit conversion(如SMALLINT柱相比,INT參數)
  • 瞭解covering indexes
  • Denormalise 之後你看問題
  • 瞭解聚合:停止循環思考
  • ...

編輯,2012年2月:

避免這些"Ten Common SQL Programming Mistakes"

+2

+1「停止思考循環」。對於大多數數據庫新手來說,基於集合的思維是最難的事情。 – 2011-05-02 15:15:32

1

我不能實際驗證您的要求,但可以說,不使用*太安靜邏輯,有什麼我可以做的就是添加一個或兩個點他們,如果你可以一起從表名中選擇一個列名添加一個where子句,它會有很大的幫助,因爲你可以減少很多不必要的行和可能被拉起的數據行,也可以避免交叉連接和歡迎內部根據我的個人經驗,連接,外連接或更充分的連接應該是順其自然的方式:)

0

添加一些提示,以列表:

使用EXISTS使用UNION時,其可以使用UNION ALL到位的/ NOT EXISTS/NOT IN的索引列

--instead of 
SELECT * FROM table1 
    WHERE id1 NOT IN (SELECT id2 FROM table2) 

--you better write 
SELECT * FROM table1 WHERE NOT EXISTS (SELECT 1 FROM table2 WHERE id1=id2) 

避免
當你不需要排除重複的行或者你確定它不會返回重複的行

避免使用HAVING當我TS可以使用WHERE

--instead of 
SELECT col1, sum(col2) 
    FROM table1 
    GROUP BY col1 
HAVING col1 > 0 

--you better write : 
SELECT col1, sum(col2) 
    FROM table1 
    WHERE col1 > 0 
GROUP BY col1 

使用,當你有一個對多表連接

--instead of 
SELECT distinct a.col1, a.col2 
    FROM table1 a, table2 b 
WHERE a.id = b.id 

--you better write 
SELECT a.col1, a.col2 
    FROM table1 a 
WHERE EXISTS (SELECT 1 FROM table2 b where a.id = b.id) 

我希望這幾個小技巧幫助,期待更多的提示exists代替DISTINCT;)

+0

我認爲現在大多數數據庫現在都爲IN和EXISTS創建相同的查詢計劃 – Magnus 2011-05-02 14:57:23

+1

@Magnus:正確,但不是IN和NOT EXISTS是非常不同的。 @mcha:你在最後一個例子中使用了ANSI-89隱式連接......應該是ANSI-92 EXPLICIT join ;-) – gbn 2011-05-02 15:21:16

+0

@gbn在SQL Server 2008上執行了一些針對NOT EXISTS和NOT IN的查詢測試,他們都制定了相同的計劃。 – Magnus 2011-05-02 15:32:31

4

有關優化查詢的幾個基本點:

  • 瞭解你的數據。瞭解你的數據。 瞭解你的信息。我冒昧猜測,所有數據庫性能問題中有一半來自對數據和查詢要求的不完全理解。知道你的查詢通常會返回50行還是500萬行。知道你是否需要找回3列或50列。知道哪些列是表格上的關鍵列,並對這些列進行過濾。

  • 瞭解您的數據庫結構。如果您使用的是第三種常規形式的數據庫,請認識到此結構通常適用於查詢在各行上操作的大量小型事務性語句。如果您在星形或雪花設計中工作,請認識到它已針對大型查詢和聚合進行了優化。

+1

@N這是最有用的! ty爲你的貢獻。然而,這個問題指向了句法優化。我毫不懷疑這就是某個語義學習者所知道的。但這不是我正在尋找的答案。 – apacay 2011-05-03 18:38:42