視窗函數會影響最佳化器考量的策略
如果子查詢具有視窗函數,則會停用子查詢的衍生資料表合併。子查詢始終會被具體化。
半聯結不適用於視窗函數最佳化,因為半聯結適用於
WHERE
和JOIN ... ON
中的子查詢,而這些子查詢不能包含視窗函數。最佳化器會依序處理具有相同排序需求的複數個視窗,因此對於第一個之後的視窗可以跳過排序。
最佳化器不會嘗試合併可以在單一步驟中評估的視窗(例如,當多個
OVER
子句包含相同的視窗定義時)。解決方法是在WINDOW
子句中定義視窗,並在OVER
子句中參考視窗名稱。
未用作視窗函數的彙總函數會在最外層的可能查詢中彙總。例如,在此查詢中,MySQL 發現 COUNT(t1.b)
是無法存在於外部查詢中的內容,因為它位於 WHERE
子句中
SELECT * FROM t1 WHERE t1.a = (SELECT COUNT(t1.b) FROM t2);
因此,MySQL 會在子查詢內部彙總,將 t1.b
視為常數,並傳回 t2
的列計數。
將 WHERE
替換為 HAVING
會導致錯誤
mysql> SELECT * FROM t1 HAVING t1.a = (SELECT COUNT(t1.b) FROM t2);
ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1
of SELECT list contains nonaggregated column 'test.t1.a'; this is
incompatible with sql_mode=only_full_group_by
發生錯誤的原因是 COUNT(t1.b)
可以存在於 HAVING
中,因此會使外部查詢成為彙總查詢。
視窗函數(包括用作視窗函數的彙總函數)沒有前面的複雜性。它們始終在其撰寫的子查詢中彙總,而絕不在外部查詢中彙總。
視窗函數評估可能會受到系統變數 windowing_use_high_precision
的值影響,該變數決定是否在不損失精度的情況下計算視窗運算。依預設,會啟用 windowing_use_high_precision
。
對於某些移動框架彙總,可以套用反向彙總函數以從彙總中移除值。這可以提高效能,但可能會損失精度。例如,將非常小的浮點數值加入非常大的值,會導致非常小的數值被大的值「隱藏」。當稍後反轉大的值時,小數值的影響會遺失。
由於反向彙總而導致的精度損失僅適用於對浮點數(近似值)資料類型進行的操作。對於其他類型,反向彙總是安全的;這包括 DECIMAL
,它允許小數部分,但屬於精確值類型。
為了加快執行速度,MySQL 在安全的情況下總是會使用反向聚合。
對於浮點數值,反向聚合並不總是安全,可能會導致精度損失。預設情況下會避免使用反向聚合,雖然速度較慢但能保留精度。如果允許為了速度而犧牲安全性,可以停用
windowing_use_high_precision
來允許反向聚合。對於非浮點數資料類型,反向聚合總是安全的,並且無論
windowing_use_high_precision
的值為何都會使用。windowing_use_high_precision
對於MIN()
和MAX()
沒有影響,因為這兩個函數在任何情況下都不會使用反向聚合。
對於變異數函數 STDDEV_POP()
、STDDEV_SAMP()
、VAR_POP()
、VAR_SAMP()
及其同義詞的評估,可以使用最佳化模式或預設模式進行。最佳化模式可能會在最後有效位數產生稍微不同的結果。如果允許這種差異,可以停用 windowing_use_high_precision
來允許使用最佳化模式。
對於 EXPLAIN
,視窗函數執行計畫資訊過於龐大,無法以傳統的輸出格式顯示。要查看視窗函數的資訊,請使用 EXPLAIN FORMAT=JSON
並查找 windowing
元素。