窗口函数优化

来自泡泡学习笔记
BrainBs讨论 | 贡献2023年8月30日 (三) 08:57的版本 (创建页面,内容为“窗口函数会影响优化器考虑的策略: * 如果子查询中包含窗口函数,则禁用派生表合并。子查询始终会被实现为物化表。 * 窗口函数优化不适用于半连接,因为半连接适用于 WHERE 和 JOIN … ON 子句中的子查询,而这些子查询不能包含窗口函数。 * 优化器会按顺序处理具有相同排序要求的多个窗口,因此对于第一个窗口后面的窗口可以跳过排序过程。 *…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳到导航 跳到搜索

窗口函数会影响优化器考虑的策略:

  • 如果子查询中包含窗口函数,则禁用派生表合并。子查询始终会被实现为物化表。
  • 窗口函数优化不适用于半连接,因为半连接适用于 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被启用。

对于某些移动框架聚合,可以应用逆向聚合函数来从聚合中去除值。这可能会提高性能,但可能会导致精度损失。例如,将一个非常小的浮点数加到一个非常大的值上,会导致这个非常小的值被这个大的值“隐藏”起来。当后续对大值进行逆向操作时,小值的影响将丢失。

逆向聚合导致精度损失只对浮点数(近似值)数据类型的操作起作用。对于其他类型,逆向聚合是安全的;这包括允许有小数部分的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,并查找窗口元素。