MySQL · 性能优化 · 条件下推到物化表

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
简介: 背景MySQL引入了Materialization(物化)这一关键特性用于子查询(比如在IN/NOT IN子查询以及 FROM 子查询)优化。具体实现方式是:在SQL执行过程中,第一次需要子查询结果时执行子查询并将子查询的结果保存为临时表 ,后续对子查询结果集的访问将直接通过临时表获得。与此同时,优化器还具有延迟物化子查询的能力,先通过其它条件判断子查询是否真的需要执行。物化子查询优化SQ

背景

MySQL引入了Materialization(物化)这一关键特性用于子查询(比如在IN/NOT IN子查询以及 FROM 子查询)优化。
具体实现方式是:在SQL执行过程中,第一次需要子查询结果时执行子查询并将子查询的结果保存为临时表 ,后续对子查询结果集的访问将直接通过临时表获得。
与此同时,优化器还具有延迟物化子查询的能力,先通过其它条件判断子查询是否真的需要执行。物化子查询优化SQL执行的关键点在于对子查询只需要执行一次。 与之相对的执行方式是对外表的每一行都对子查询进行调用,其执行计划中的查询类型为“DEPENDENT SUBQUERY”。

在使用Materialization(物化)能提高SQL性能的同时,也有必要留意相关SQL是否存在进一步优化空间的可能性。比如下面描述的场景:

mysql>explain extended Select * from (select * from score where score >= 60) derived1 where class_id  = 10;
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+----------+--------------------------+
| id | select_type | table      | type  | possible_keys | key         | key_len | ref   | rows | filtered | Extra                    |
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+----------+--------------------------+
| 1  | PRIMARY     | <derived2> | ref   | <auto_key0>   | <auto_key0> | 4       | const | 0    |      100 |                          |
| 2  | DERIVED     | score      | index | idx_score     | idx_score   | 4       |       | 1    |      100 | Using where; Using index |
+----+-------------+------------+-------+---------------+-------------+---------+-------+------+----------+--------------------------+

从执行计划可看出,MySQL首先物化了子查询(select_type=DERIVED,或者以format=json格式查看执行计划),然后再通过class_id字段对结果集进行过滤。这个SQL从语义上,也可以写成如下形式,若索引合理执行效率会更高。

select * from score where score >= 60 and class_id=10

从这个例子可以看出子查询物化时的一个潜在问题:当子查询本身比较耗费资源或结果集较大时,往往存在较高的优化空间,特别是在外层条件可作用于子查询的情况下。通过条件下推,在执行过程中尽早减少数据访问量,能显著提高性能。本文重点描述将条件下推到物化子查询的场景。

分析

事实上前面提到的查询在5.7版本可以自动重写。打开优化器选项 derived_merge=on 后,查看重写后的语句如下:

select `remall`.`score`.`class_id` AS `class_id`,`remall`.`score`.`student_id` AS `student_id`,`remall`.`score`.`score` AS `score` 
from `remall`.`score` 
where ((`remall`.`score`.`class_id` = 10) and (`remall`.`score`.`score` >= 60))

另一方面,并不是所有子查询可以做到自动条件下推。比如下面这个语句:

select * from (select class_id, avg(score) from score group by class_id) derived1 where class_id  = 10;

出现这种现象的原因是MySQL优化器目前只能对Mergable的视图或子查询进行重写。理解这一概念可以先从视图的两种算法入手:merge 和 temptable。

一般较为复杂的视图或子查询会使用temptable算法类型,包括:
1. 聚合子查询;
2. 含有LIMIT的子查询;
3. UNION 或UNION ALL子查询;
4. 输出字段中的子查询;

我们也可以显示的通过创建视图来判断子查询是否使用了merge算法。 比如:

mysql>create algorithm=merge view v as select class_id, avg(score) from score group by class_id;
执行成功,花费 2.46 ms.
mysql>show warnings;
+---------+------+-------------------------------------------------------------------------------+
| Level   | Code | Message                                                                       |
+---------+------+-------------------------------------------------------------------------------+
| Warning | 1354 | View merge algorithm can't be used here for now (assumed undefined algorithm) |
+---------+------+-------------------------------------------------------------------------------+

我们创建视图时指定使用merge,但是数据库判定该算法不适合因此使用默认的undefined(实际执行过程中使用temptable算法)。

/**
  Strategy for how to process a view or derived table (merge or materialization)
*/
enum enum_view_algorithm {
  VIEW_ALGORITHM_UNDEFINED = 0,
  VIEW_ALGORITHM_TEMPTABLE = 1,
  VIEW_ALGORITHM_MERGE     = 2
};

使用merge算法的视图或子查询能够将查询条件下推到视图或子查询内部;而temptable算法子查询或视图不能将条件下推,只能在结果集上做进一步过滤。优化器对对这一判断标准为:

bool merge_derived(THD *thd, TABLE_LIST *derived_table)
{
...
  // Check whether derived table is mergeable, and directives allow merging
  if (!derived_unit->is_mergeable() ||
      derived_table->algorithm == VIEW_ALGORITHM_TEMPTABLE ||
      (!thd->optimizer_switch_flag(OPTIMIZER_SWITCH_DERIVED_MERGE) &&
       derived_table->algorithm != VIEW_ALGORITHM_MERGE))
    DBUG_RETURN(false);
...
}

条件下推原则

不是所有数据库引擎都完美实现条件下推下推到子查询的功能。对MySQL中使用聚合查询的视图或者from子查询,建议的条件下推原则是:

       查询中只依赖于视图或者from子查询输出字段的where 条件能够安全的下推。

同时需要注意条件下推到视图或derived table子查询后所存放的恰当位置:

  1. 从语义上看,下推到聚合子查询的条件可以放在 HAVING 子句里。下推后的 HAVING字句可以是: HAVING xxx and NEW_CONDITION operation VALUE;
  2. 若条件是子查询的group 字段,且该条件上有索引,那么将该条件放在子查询的where字句中,性能会更好(HAVING条件中不含聚合函数时,将该条件下推到where字句中过滤整个group)。

对于其他类型的视图或from子查询,也可以通过语义检查的方式进行人工条件下推。

总结

任何数据库的优化器都不是万能的。 了解优化器的特性后并规避其短处,才能写出最优SQL语句。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
8月前
|
关系型数据库 MySQL 数据库
数据迁移脚本优化过程:从 MySQL 到 Django 模型表
在大规模的数据迁移过程中,性能问题往往是开发者面临的主要挑战之一。本文将分析一个数据迁移脚本的优化过程,展示如何从 MySQL 数据库迁移数据到 Django 模型表,并探讨优化前后的性能差异。
|
3月前
|
存储 缓存 负载均衡
mysql的性能优化
在数据库设计中,应选择合适的存储引擎(如MyISAM或InnoDB)、字段类型(如char、varchar、tinyint),并遵循范式(1NF、2NF、3NF)。功能上,可以通过索引优化、缓存和分库分表来提升性能。架构上,采用主从复制、读写分离和负载均衡可进一步提高系统稳定性和扩展性。
58 9
|
5月前
|
存储 SQL 关系型数据库
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
MySQL调优主要分为三个步骤:监控报警、排查慢SQL、MySQL调优。 排查慢SQL:开启慢查询日志 、找出最慢的几条SQL、分析查询计划 。 MySQL调优: 基础优化:缓存优化、硬件优化、参数优化、定期清理垃圾、使用合适的存储引擎、读写分离、分库分表; 表设计优化:数据类型优化、冷热数据分表等。 索引优化:考虑索引失效的11个场景、遵循索引设计原则、连接查询优化、排序优化、深分页查询优化、覆盖索引、索引下推、用普通索引等。 SQL优化。
880 15
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
|
4月前
|
存储 关系型数据库 MySQL
MySQL性能优化实践指南
【10月更文挑战第16天】MySQL性能优化实践指南
382 0
|
4月前
|
存储 关系型数据库 MySQL
MySQL性能优化指南
【10月更文挑战第16天】MySQL性能优化指南
533 0
|
5月前
|
存储 关系型数据库 MySQL
mysql-性能优化(一)
mysql-性能优化(一)
|
5月前
|
关系型数据库 MySQL 数据处理
针对MySQL亿级数据的高效插入策略与性能优化技巧
在处理MySQL亿级数据的高效插入和性能优化时,以上提到的策略和技巧可以显著提升数据处理速度,减少系统负担,并保持数据的稳定性和一致性。正确实施这些策略需要深入理解MySQL的工作原理和业务需求,以便做出最适合的配置调整。
611 6
|
5月前
|
SQL 存储 关系型数据库
深入 MySQL 的执行计划与性能优化
深入 MySQL 的执行计划与性能优化
59 0
|
6月前
|
存储 关系型数据库 MySQL
"深入探索MySQL临时表:性能优化利器,数据处理的灵活之选"
【8月更文挑战第9天】MySQL临时表专为存储临时数据设计,自动创建与删除,仅在当前会话中存在,有助于性能优化。它分为本地临时表和全局临时表(通过特定逻辑模拟)。创建语法类似于普通表,但加TEMPORARY或TEMP关键字。适用于性能优化、数据预处理和复杂查询,需注意内存占用和事务支持问题。合理使用可大幅提升查询效率。
395 2
|
7月前
|
SQL 存储 数据库
MySQL设计规约问题之性能分析工具如Sql explain、show profile和mysqlsla在数据库性能优化中有什么作用
MySQL设计规约问题之性能分析工具如Sql explain、show profile和mysqlsla在数据库性能优化中有什么作用

相关产品

  • 云数据库 RDS MySQL 版