最近,我正在通過 SQL 腳本作為檢查資料科學程序功能的任務的一部分。我有一個腳本部分的副本,其中有多個子查詢,我重構了它,將子查詢放在 with 子句的頂部。我通常認為這是一種本質上是語意中立的句法重構操作。但是,腳本的操作發生了變化。
調查表明,這是由于在磁區內的排序不完整的磁區上使用了行號。改變代碼的結構改變了執行計劃中的一些東西,改變了不完整排序留下的松弛中的順序。
我記下了這一點,對這次重構變得不那么自信了,盡管我認為順序不應該影響語意,至少只要可以避免。
我的問題是...
除了分配行號之外,哪些操作的值會因排序而改變?
uj5u.com熱心網友回復:
所以你是說在 中有間隙row_numbers()?或重復的row_numbers?或者只是行號跳來跳去(不穩定?)
哪些函式被函式的不完整/不穩定的順序改變,所有那些你把 OBER BY 放在視窗函式中的函式。因此 ROW_NUMBER 或 LAG 或 LEAD
但一般來說,子選擇和 CTE(帶子句)是相同的,主要區別在于多個事物可以加入同一個 CTE(因此是公共部分),這可能是好的/壞的,因為您可能會節省一些昂貴的計算,但您也可能會減慢關鍵路徑的速度,并使整個執行時間變慢。
或者資料可能會被更多地處理(由于 JOIN 等),然后可能會暴露不完整的 ODERBY/不穩定性。
uj5u.com熱心網友回復:
當涉及視窗函式時,尤其ROW_NUMBER()要檢查的第一件事是用于排序的列是否產生穩定的排序。
例如:
CREATE TABLE t(id INT, grp VARCHAR(100), d DATE, val VARCHAR(100));
INSERT INTO t(id, grp, d, val)
VALUES (1, 'grpA', '2021-10-16', 'b')
,(2, 'grpA', '2021-10-16', 'a')
,(3, 'grpA', '2021-10-15', 'c')
,(4, 'grpA', '2021-10-14', 'd')
,(5, 'grpB', '2021-10-13', 'a')
,(6, 'grpB', '2021-10-13', 'g')
,(7, 'grpB', '2021-10-12', 'h');
-- the sort is not stable, d column has a tie
SELECT *
FROM (
SELECT t.*, ROW_NUMBER() OVER(PARTITION BY grp ORDER BY d DESC) AS rn
FROM t) sub
WHERE sub.rn = 1 AND sub.val = 'a';

根據操作順序,它可能回傳:
- 0 行
- 1 行(編號:2)
- 1 行(編號:5)
- 2 行(編號:2 和 5)
當查詢被重構時,它可能會導致選擇不同的路徑來訪問資料,從而導致不同的結果。
要檢查排序是否穩定,可以使用所有可用列使用視窗 COUNT:
SELECT *
FROM (
SELECT t.*, COUNT(*) OVER(PARTITION BY grp, d ) AS cnt
FROM t) sub
WHERE cnt > 1;
db<>小提琴演示
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/314303.html
