窗口函数会影响优化器考虑的策略
如果子查询包含窗口函数,则禁用子查询的派生表合并。子查询总是被物化。
半连接不适用于窗口函数优化,因为半连接适用于
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
元素。