2011-02-10 46 views
5

所以我試圖解釋有些人爲什麼這個查詢是一個壞主意:在SQL Server中,在具有聚簇索引的表上使用時,默認爲TOP確定性?

SELECT z.ReportDate, z.Zipcode, SUM(z.Sales) AS Sales, 
COALESCE(
    (SELECT TOP (1) GroupName 
    FROM dbo.zipGroups 
    WHERE (Zipcode = z.Zipcode)), 'Unknown') AS GroupName, 
COALESCE(
    (SELECT TOP (1) GroupCode 
    FROM dbo.zipGroups 
    WHERE (Zipcode = z.Zipcode)), 0) AS GroupNumber 
FROM dbo.Report_ByZipcode AS z 
GROUP BY z.ReportDate, z.Zipcode 

,並提出一個更好的方式來寫它,當我的老闆結束了,「好了,它已經返回討論對於去年的正確數據,我們沒有任何問題,所以沒關係。「

在哪一刻我想到了自己,在這個世界上,甚至有可能如何?

一些挖後,我發現了這些事實:

  1. 此查詢通過郵政編碼和日期應該組銷售,並鏈接那些最大的羣體(按人口規模),一個郵政編碼被分配到zipGroups表的方式。
  2. 每個Zipcode可以分配給0到多個組,並且如果一個Zipcode分配給0個組,它就不在zipGroups表中。
  3. 集團是一個地理區域,集團數量按人口按照最大到最小排列(例如,覆蓋NY-NJ-CT三州地區的組是GroupNumber 1,內布拉斯加州North Platte是GroupNumber 209 )。
  4. zipGroups表格在至少2年內沒有變化。
  5. zipGroups表具有帶Zipcode,GroupNumber(升序)作爲鍵的聚集索引。
  6. Zipcode,GroupNumber的組合在zipGroups中是唯一的。

所以我的問題有2個部分。

A)即使這些SELECT TOP查詢中沒有ORDER BY子句,它們是否確實是確定性的,因爲聚集索引基本上是爲其提供默認的ORDER BY? B1)如果這是真的,那麼查詢然而不穩定,實際上是在做它應該做的事情嗎? B2)如果不是這樣,你能幫我證明一下嗎?

注:我已經重寫了這個使用連接,所以我不需要SQL來解決它,我需要把它投入生產,所以我不再擔心它打破。

+0

簡單而簡單:如果沒有'ORDER BY',任何訂單都不能保證** –

+0

棘手的問題:對老闆說「這很好」該怎麼說。 –

+0

即使從實際的角度來看,查詢優化器目前不會做任何其他事情,但它在邏輯上並不確定。如果你需要一個特定的行爲,你應該指定它,否則下一個服務包/版本你的查詢可能會中斷(在視圖中使用'TOP 100 PERCENT'或者使用變量來連接字符串。這看起來毫無意義的風險,因爲沒有明顯的好處。 –

回答

4

對於缺少ORDER BY的記錄排序,SQL Server不作任何保證。它可能產生999,999次的正確結果,然後在百萬次嘗試中失敗。不要這樣做。

+0

哦,遠遠超過百萬分之一 – RichardTheKiwi

+1

@cyberwiki:當你說「更多」時,我不確定你是指分子還是分母,因此我不能說出你的創作點(你我想可能意味着兩種情況;根據具體情況,我們可以看到failure_rate >>> 1e-6或failure_rate <<< 1e-6)。 –

1

始終按照TOP語句使用訂單。該訂單不保證按照本博客文章中所示的聚集索引的順序進行(使用反駁它的查詢完成):

Without ORDER BY, there is no default sort order

即使它通過聚簇索引,我也不會編寫依賴於數據庫引擎的未記錄行爲的查詢,並且爲了便於閱讀,最好是明確的。

+0

鏈接的文章和其他幾種處理優化程序選擇使用哪個索引時的情況。如果只給出1個選擇,並且TOP N固定在N = 1,則它更可預測。 – RichardTheKiwi

+0

這就是爲什麼我upvoted你的答案。不過,我認爲依賴查詢優化器的未記錄行爲是一個壞主意,即使它看起來可行。 – JohnFx

0

A)即使這些SELECT TOP查詢中沒有ORDER BY子句,它們是否確實是確定性的,因爲聚集索引基本上是爲它提供一個默認的ORDER BY? B1)如果這是真的,那麼查詢是不是很危險,實際上是在做它應該做的事情?

當沒有排序指定top時,排序是查詢優化器選擇的訪問方法的副作用。由於查詢優化器將使用聚集索引來解決此查詢,因此您會得到相當好的副作用。

我不會使用deterministic這個詞,因爲查詢優化器可能不是確定性的。但是,在優化器選擇聚集索引的情況下,是的 - 查詢執行它應該做的事情。

應該仍然指定ORDER,以便將正確性鎖定到查詢中。你應該分別將正確性(「你想要什麼」)和實現(「你如何得到它」)分別放入查詢和優化器計劃中。

B2)如果那不是真的,你能幫我證明嗎?

假設有在ZipGroups表更多的列,可以加入含有僅有的兩個相關列非聚集索引將是優選在聚簇索引。如果非聚簇索引具有不同的順序(Zipcode asc,GroupNumber desc),那麼查詢將會中斷。

+0

'你有一個相當不錯的副作用'不是100%真實的。即使選擇了聚集索引,也不能保證訂單(在該索引上) – RichardTheKiwi

+0

當然不能保證。但是在那裏有一些實現,如果它的行爲不同,實現會很奇怪(當然,並行性總是很奇怪)。 –

1

如果您依賴的是聚集索引而不是排序規則,那麼獲取正確的順序是巧合的,而不是確定性的。

在現實世界中,索引可以從一種改變到另一種,原因很好,原因很糟糕,或根本沒有理由。而且,在現實世界中,您不一定會選擇SQL Server在執行查詢時使用的索引。 (或者它是否會使用索引。)

從技術上講,排序規則也可以因爲很好的理由,不好的理由或根本沒有理由而改變。但每個人知道更改排序規則將改變排序順序 - 畢竟這是它的工作 - 所以這並不意外。 (曾聽說過「最小驚喜原則」?)

1

JohnFx的鏈接很好,雖然很長,很難遵循。這是它自己的一個小片段,它將顯示以非聚集索引順序返回的數據。

CREATE TABLE t1 (x INT NOT NULL PRIMARY KEY CLUSTERED, z INT NOT NULL UNIQUE); 

INSERT INTO t1 (x,z) VALUES (1,4); 
INSERT INTO t1 (x,z) VALUES (3,3); 
INSERT INTO t1 (x,z) VALUES (2,2); 
INSERT INTO t1 (x,z) VALUES (4,1); 

SELECT x, z FROM t1; 

輸出(你應該)

x   z 
----------- ----------- 
4   1 
2   2 
3   3 
1   4 

執行規劃顯示它採用獨特的(或其他)的索引而不是聚集索引。

即使選擇了聚簇索引,如果數據是從並行化合並的,如果TOPN數量足夠高,它可能無法正確排序。

說了這麼多,因爲你只使用TOP(1)如果表中有只有一個索引可用的,也可以是考慮確定性,因爲它只會使用該索引並挑選索引頁面中的第一個條目。

+0

所以 - 因爲這個查詢是「被認爲是確定性的」,他應該通知他的老闆「沒事」是真的嗎? –

+0

@David - 是的,在這種情況下,在SQL Server的所有當前實現中,直到2008 R2 – RichardTheKiwi

+0

[「高級掃描」](http://msdn.microsoft.com/zh-cn/library/ms191475 .aspx)不能在這裏適用? –

相關問題