Microsoft SQL Server 2014 從交叉應用中的查詢嵌套
從 OUTER APPLY 語句中的嵌套查詢中進行選擇時,嵌套查詢似乎在某些情況下只被評估一次。
向 Azure 回饋論壇報告的錯誤:https ://feedback.azure.com/forums/908035-sql-server/suggestions/39428632-microsoft-sql-server-2014-incorrect-result-when-s
這是預期的行為,還是我在文件中遺漏了什麼,或者這是 SQL Server 中的錯誤?
此外,是否有可能強制評估每一行的嵌套查詢?
測試案例 1
評估 VALUES 中每一行的嵌套 FROM 查詢(恕我直言預期行為)
SELECT v, v2 FROM (VALUES (1), (2), (3), (4)) AS inner_query(v) OUTER APPLY ( SELECT MAX(inner_v2) AS v2 FROM ( SELECT 15 AS id, v AS inner_v2 ) AS outer_query GROUP BY id ) AS outer_apply
結果:
| v | v2| |---|---| | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 |
測試案例 2
它還評估 VALUES 中每一行的嵌套 FROM 查詢(恕我直言預期行為)
SELECT v, v2 FROM (VALUES (1), (2), (3), (4)) AS inner_query(v) OUTER APPLY ( SELECT MAX(inner_v2) AS v2 FROM ( SELECT 15 AS id, v AS inner_v2 UNION ALL SELECT id AS id, TestCaseTemp2.v AS inner_v2 FROM (VALUES (1337, 0)) AS TestCaseTemp2(id, v) WHERE TestCaseTemp2.v != 0 ) AS outer_query GROUP BY id ) AS outer_apply;
結果:
| v | v2| |---|---| | 1 | 1 | | 2 | 2 | | 3 | 3 | | 4 | 4 |
測試案例 3
只計算一次嵌套的 FROM 查詢
CREATE TABLE TestCaseTemp ( id int, v int ); INSERT INTO TestCaseTemp VALUES (1337, 0); SELECT v, v2 FROM (VALUES (1), (2), (3), (4)) AS inner_query(v) OUTER APPLY ( SELECT MAX(inner_v2) AS v2 FROM ( SELECT 15 AS id, v AS inner_v2 UNION ALL SELECT id AS id, TestCaseTemp.v AS inner_v2 FROM TestCaseTemp WHERE TestCaseTemp.v != 0 ) AS outer_query GROUP BY id ) AS outer_apply; DROP TABLE TestCaseTemp;
結果:
| v | v2| |---|---| | 1 | 1 | | 2 | 1 | | 3 | 1 | | 4 | 1 |
這是 SQL Server 中的錯誤嗎?
是的,當然,
1
最終結果中所有行中返回的 僅存在於外部輸入的第一行中,因此甚至不應該在後續行的範圍內。它看起來與 Paul White在這裡詳細討論的基本問題相同。我在 dbfiddle (SQL Server 2019) 中執行了您的最終查詢並在此處粘貼了計劃https://www.brentozar.com/pastetheplan/?id=Sy4sBB5lI 看起來排序執行了 4 次(每個外行一次)但是對於出於某種原因,它會倒帶而不是重新綁定,因此不會多次呼叫該排序的子運算符。這是一個錯誤,因為對外部連接 ( ) 的相關參數的引用
Union1004
應該會在其值更改時導致重新綁定。因此,Union1004
從未重新評估計劃節點 5 中的引用。是否有可能強制評估每一行的嵌套查詢?
添加查詢提示
OPTION (MERGE UNION)
適用於您的範例,我不知道這是否足以在所有情況下避免該錯誤,但從連結的 Paul White 答案看來它應該可以工作。在您的範例中,它的工作原理是排序在計劃中被向下推,因此它只會倒回TestCaseTemp
行,而不是整個聯合結果。您還可以添加適當的索引以完全刪除排序。