視窗函數會影響最佳化工具所考慮的策略
如果子查詢具有視窗函數,則會停用子查詢的衍生表合併。子查詢一律會實體化。
半聯結不適用於視窗函數最佳化,因為半聯結適用於
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
元素。