19.1 并行查询(PQ)
19.1.1 特性使用介绍
19.1.1.1 特性使用约束
目前,并行执行在使用过程中存在一些限制,后续会逐步进行解决。
不适用并行执行的情况
下列的查询语句不支持并行执行:
● 非查询语句
● 窗口函数
● 触发器Trigger
● 空间索引Spatial index
● 查询表为系统表/临时表/非Innodb表
● 使用全文索引
● 存储过程Procedures
● 不能转换成semijoin的子查询
● Materialization simi-join
● 包含特殊字段,或者函数结果转换成特殊字段 (BLOB, JSON和GEOMETRY)
● With语句
● 使用索引归并Index merge
● 串行化隔离级别事务内的查询语句
● 带有distinct关键字的查询语句
● Require locking, such as serializable isolation level, for updata/share lock
● Attachable transaction
● 并行内存超过parallel_memory_limit限制
● 并行线程超过parallel_max_threads限制
● 执行代价未超过parallel_cost_threshold
● 递归查询
● With rollup
● 存在HIGH_PRIORITY关键字
● 执行结果返回0行数据(执行计划显示:Zero limit、Impossible WHERE、
Impossible HAVIN、No matching min/max row、No matching min/max row、Select tables optimized away、Impossible HAVING noticed after reading const tables、no matching row in const table等)
● TP高吞吐短查询模型
● group by/order by中的列是查询表达式中重命名的列
● group by中扫描代价超过非并行的语句
● 查询中包含zerofill的列,并且这些列能被优化为常量 说明
与之前的版本相比,MySQL 8.0.22版本支持了部分特性,具体如下所示:
● UNION/UNON ALL语句。
● Duplicateweedout类型的semijoin。
● Group by优化成索引扫描,并且select中包含函数表达式。
● Having中包含聚合函数
● select表达式中包含聚合函数计算,例如SUM(a)/AVG(b)。
● JOIN查询, 拆分表为内表,并且该表上是ref查询。
与串行执行结果可能不兼容
并行执行的执行结果可能存在与串行执行不兼容的情况,主要表现在:
● 错误或者告警提示次数可能会增多
对于在串行执行中出现错误/告警提示的查询,在并行执行情况下,每个工作线程 可能都会提示错误/告警,导致总体错误/告警提示数会增多。
● 精度问题
并行执行的执行过程中,当select的内容是函数类型时,会比非并行执行多出中间 结果的存储过程,可能会导致浮点部分精度差别,导致最终结果有细微的差别。
● 截断问题
并行执行的执行过程中,当select的内容是函数类型时,会比非并行执行多出中间 结果的存储过程。在这个过程中,需要缓存函数的计算结果,可能出现截断(一般 是类型转换导致的,例如浮点数类型转为字符串等), 导致最终结果与串行结果有 差别。
● 结果集顺序差别
因为是多个工作线程执行查询,返回的结果集可能与非并行执行顺序不一致。在 具有LIMIT查询的情况下,更容易出现与串行结果顺序不同的现象。对于不可见字 符,当MySQL判断多个不可见字符相等时,可能会出现结果集顺序不同,或者 group by字段不同的现象。
19.1.1.2 支持的函数、参数和变量 支持的函数
并行查询语句主要支持以下函数:
● GROUP BY
● ORDER BY
● AGGREGATION (SUM/AVG/COUNT)
● LIMIT
● WHERE/HAVING
● LIKE
● INTERVAL
● CASE WHEN
● JOIN
支持的系统参数和状态变量
表19-1 系统参数
参数名 级别 描述
force_parallel_exe
cute Global, Session 强制进入并行执行,尽可能地使用并行执 行。
· 取值范围:ON, OFF
· 默认值OFF parallel_max_thre
ads Global 并行执行的最大活跃线程个数。当并行执行 的活跃线程超过该值时,新的查询将不允许 启用并行执行。
· 取值范围:0-4294967295
· 默认值:64 parallel_default_d
op Global, Session 并行执行的默认并行度。当查询语句没有指 定并行度时,使用该值。
· 取值范围:0-1024
· 默认值:4 parallel_cost_thre
shold Global, Session 启用并行执行的代价阈值。只有当查询的估 计代价超过该阈值时才有可能进行并行执 行。
· 取值范围:0-4294967295
· 默认值:1000 parallel_queue_ti
meout Global, Session 请求并行执行的SQL的等待时间。如果超过 该值后,并行执行的线程数仍然大于 parallel_max_threads,则不再等待而进入 单线程执行。
· 取值范围:0-4294967295
· 默认值:0
参数名 级别 描述 parallel_memory_
limit Global 并行执行可用的内存上限。当并行执行使用 的内存量超过该值时,新的SQL查询将不会 进行并行执行。
· 取值范围:0-4294967295
· 默认值:104857600
表19-2 状态变量
变量名 级别 描述
PQ_threads_runnin
g Global 当前正在运行的并行执行的总线程数。
PQ_memory_used Global 当前并行执行使用的总内存量。
PQ_threads_refuse
d Global 由于总线程数限制,导致未能执行并行执行
的查询总数。
PQ_memory_refus
ed Global 由于总内存限制,导致未能执行并行执行的 查询总数。
19.1.1.3 开启/关闭并行查询
通过设置系统参数和使用hint语法两种方式,开启/关闭并行查询。
方法一:通过设置系统参数开启/关闭并行查询
在管理控制台的参数修改页面,通过设置系统参数开启和关闭并行查询,并设置并行 度。
通过全局参数force_parallel_execute来控制是否强制启用并行执行;
使用全局参数parallel_default_dop来控制使用多少线程并行执行;
使用全局参数parallel_cost_threshold来控制当数据规模为多大时开启并行执行。
上述参数在使用过程中,随时可以修改,无需重启数据库。
例如,想要强制开启并行执行,并且并发度为4:
SET force_parallel_execute=1;
SET parallel_default_dop=4;
SET parallel_cost_threshold=0;
方法二:使用 hint 开闭/关闭并行查询
使用hint语法可以控制单个语句是否进行并行执行。在系统默认关闭并行执行的情况 下, 可以使用hint对特定的SQL进行加速。反之,也可以限制某类SQL进入并行执行。
开启并行执行:采用下面的hint语法可以开启并行执行。
采用默认的拆分表和并发度(默认值取parallel_cost_threshold):SELECT /*+ PQ()
*/ … FROM …
采用默认的拆分表,但是指定并发度为8:SELECT /*+ PQ(8) */ … FROM … 采用默认的并发度,但是指定拆分表为t1:SELECT /*+ PQ(t1) */ … FROM … 指定拆分表为t1,并发度为8:SELECT /*+ PQ(t1 8) */ … FROM …
说明
PQ hint紧跟着SELECT关键字才能生效。PQ hint的并发度参数dop应满足:dop>0,否则此hint 不生效,如PQ(0)不生效;当dop>1024时,dop取最大并发度1024。当使用PQ hint时,支持多 表查询。
关闭并行执行:可以采用"NO_PQ"的hint语法关闭并行执行。
SELECT /*+ NO_PQ */ … FROM …
19.1.1.4 查看特性状态
状态显示
通过show status like "%PQ%",显示并行执行的当前状态,显示结果请见图1:
图19-2 状态显示
并行执行计划展示
通过Explain展示查询语句的并行执行计划,显示结果请见图2:
图19-3 并行执行计划结果展示
说明
与传统的执行计划,并行执行计划多了一行记录。在查询结果的第一行,展示了并发度、拆分表 等信息。对于Explain format=json和Explain format=tree格式,并行执行目前还不支持。
19.1.1.5 并行执行中多表支持介绍
并行执行新增支持多表join查询功能,并且新增hint语法控制单条语句并行执行开启或 关闭。
多表支持限制
并行执行多表join支持:
● BNL(hash join)
● BKA
● Semijoin Firstmatch, loosescan和DuplicateWeedout
● outer join(仅支持拆分外表)
并行执行多表join不支持的方式:
● Semijoin Materialization
● 不能转换成semijoin的子查询
● Join的表有相同的alias 并行执行不支持的数据类型:
● generated column
● BLOB(TINYBLOB, BLOB, MEDIUMBLOB, and LONGBLOB等)
● TEXT
● JSON
● GEOMETRY
并行执行不支持的函数:
● Spatial相关函数(如SP_WITHIN_FUNC等)
● aggregation(distinct)(如sum(distinct)、avg(distinct)、count(distinct))
● GROUP_CONCAT
● JSON_ARRAYAGG/JSON_OBJECTAGG
● 用户自定义函数
● STD/STDDEV/STDDEV_POP
● VARIANCE/VAR_POP/VAR_SAMP
● BIT_AND, BIT_OR and BIT_XOR
● set_user_var
● rand(不含参数的除外)
● json_*(如json_length,json_type等)
● st_distance
● get_lock
● is_free_lock,is_used_lock,release_lock, release_all_locks
● sleep
● xml_str
● weight_string
● ref函数(VIEW_REF, OUTER_REF, AGGREGATE_REF),
● SHA,SHA1,SHA2,MD5
拆分表选择策略
1. 优先选择hint指定的表,并坚持是否能作为拆分表。
2. 若未使用PQ HINT指定拆分表,或者hint指定的表不能作为拆分表,则选择行记 录最多的表(根据统计信息中row_fetched)。
3. 若行记录最多的表不能作为拆分表,则选择行记录次数多的。
4. 直到选择一个能拆分的表,则选择此表作为拆分表,进行并行执行。或者全部表 都不支持拆分,不走并行执行。
拆分表选择限制
不支持作为拆分表的表类型:
● 非table/index/range scan
● outer join的内表
● const/system不支持拆分
● 可为空(nullable)的表不支持拆分
● skip scan
可能出现的性能退化
● 表数据量过小
在小表上启用并行查询,此场景下有性能退化。
● 拆分表选择不合适
由于拆分表选择上有限制,有些场景下只能选择最外层的表作为拆分表,但是此 表可能只存在几行数据,不能充分利用所有worker线程,并行性能退化。