并行查询
POLARDB MySQL 8.0重磅推出并行查询框架,当您的查询数据量到达一定阈值,就会自动启动并行查询框架,从而使查询耗时指数级下降。
在存储层将数据分片到不同的线程上,多个线程并行计算,将结果流水线汇总到总线程,最后总线程做些简单归并返回给用户,提高查询效率。
并行查询(Parallel Query)利用多核CPU的并行处理能力,以8核 32G 配置为例,示意图如下所示:
应用场景
并行查询适用于大部分SELECT语句,例如大表查询、多表连接查询、计算量较大的查询。对于非常短的查询,效果不太显著。
- 轻分析类业务
报表查询通常SQL复杂而且比较耗费时间,通过并行查询可以加速单次查询效率。
- 系统资源相对空闲
并行查询会使用更多的系统资源,只有当系统的CPU较多、IO负载不高、内存够大的时候,才可以充分使用并行查询来提高资源利用率和查询效率。
性能优势
关于并行查询的性能优势,请参见并行查询使用示例。
并行查询的使用方法
- 通过系统参数来控制并行查询
POLARDB通过Global全局参数 max_parallel_degree 来控制每一条SQL最多使用多少个线程并行执行,默认值是4,您可以在使用过程中随时修改该参数(参见设置集群参数),无需重启数据库。
除了Global集群级别,您也可以单独调整某Session内SQL查询的并行度。例如,通过Session级环境变量,加到JDBC的连接串配置中,则可以对某个应用程序单独设置并行度。set max_parallel_degree = n
- 使用 Hint
使用Hint开启并行查询(n代表最大的并行度,也就是最大的worker个数):
SELECT /*+ SET_VAR(max_parallel_degree=n) */ * FROM ...
说明 为了发挥最佳性能,并行查询并不是对所有的SQL都生效,POLARDB优化器会根据具体的查询SQL生成合适的执行计划。 - 强制优化器选择并行执行
POLARDB优化器可能不选择并行执行查询,如果希望优化器忽略代价,尽可能选择并行计划,可以设置如下参数:
set force_parallel_mode = on
说明 这是一个调试参数,不建议在生产环境中使用。由于并行查询使用场景的限制,有些情况下即便设置了该参数,优化器也可能不选择并行。
相关参数和变量
参数名 | 级别 | 描述 |
---|---|---|
max_parallel_degree | Global、Session |
单个查询的最大并行度,即最多使用多少个worker进行并行执行。
说明 POLARDB优化器可能会对主查询和子查询分别并行执行,如果同时并行执行,它们的最大worker数不能超过max_parallel_degree,整个查询使用的worker数将会是主查询和子查询使用的worker数之和。
|
force_parallel_mode | Session |
强制POLARDB优化器忽略代价,尽可能的使用并行查询。
注意 这是个调试参数,打开后,POLARDB优化器会尽可能的选择并行查询,但不能保证一定使用并行查询。
|
变量名 | 级别 | 描述 |
---|---|---|
Parallel_workers_created | Session、Global | 从Session启动开始,生成Parallel Worker的个数。 |
Gather_records | Session、Global | Gather记录总数。 |
PQ_refused_over_memory_soft_limit | Session、Global | 由于内存限制没有启用并行的查询数。 |
PQ_refused_over_total_workers | Session、Global | 由于总Worker数限制没有启用并行的查询数。 |
Total_used_query_memory | Global | 当前总的已使用的查询内存(Virtual Memory)。 |
Total_running_parallel_workers | Global | 当前正在运行的Parallel Worker的数目。 |
并行执行计划
以下为您介绍EXPLAIN执行计划输出中与并行查询相关的内容。
- 并行扫描
在并行扫描中,每个Worker并行独立扫描数据表中的数据。Worker扫描产生的中间结果集将会返回给Leader线程,Leader线程通过Gather操作收集产生的中间结果,并将所有结果汇返回到客户端。
- 多表并行连接
并行查询会将多表连接操作完整的下推到Worker上去执行。POLARDB优化器只会选择一个自认为最优的表进行并行扫描,而除了该表外,其他表都是一般扫描。每个Worker会将连接结果集返回给Leader线程,Leader线程通过Gather操作进行汇总,最后将结果返回给客户端。
- 并行排序
POLARDB优化器会根据查询情况,将ORDER BY下推到每个Worker里执行,每个Worker将排序后的结果返回给Leader,Leader通过Gather Merge Sort操作进行归并排序,最后将排序结果返回到客户端。
- 并行分组
POLARDB优化器会根据查询情况,将GROUP BY下推到Worker上去并行执行。每个Worker负责部分数据的GROUP BY。Worker会将GROUP BY的中间结果返回给Leader,Leader通过Gather操作汇总所有数据。这里POLARDB优化器会根据查询计划情况来自动识别是否需要再次在Leader上进行GROUP BY。例如,如果GROUP BY使用了Loose Index Scan,Leader上将不会进行再次GROUP BY;否则Leader会再次进行GROUP BY操作,然后把最终结果返回到客户端。
- 并行聚集
并行查询执行聚集函数下推到Worker上并行执行。并行聚集是通过两次聚集来完成的。第一次,参与并行查询部分的每个Worker执行聚集步骤。第二次,Gather或Gather Merge节点将每个Worker产生的结果汇总到Leader。最后,Leader会将所有Worker的结果再次进行聚集得到最终结果。
并行执行计划示例
以下以使用pq_test表来测试并行查询为例。
表结构如下:
mysql> SHOW CREATE TABLE pq_test\G
*************************** 1. row ***************************
Table: pq_test
Create Table: CREATE TABLE `pq_test` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`help_topic_id` INT(10) UNSIGNED NOT NULL,
`name` CHAR(64) NOT NULL,
`help_category_id` SMALLINT(5) UNSIGNED NOT NULL,
`description` TEXT NOT NULL,
`example` TEXT NOT NULL,
`url` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21495809 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
表大小如下:
mysql> SHOW TABLE STATUS\G
*************************** 1. row ***************************
Name: pq_test
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 20064988
Avg_row_length: 1898
Data_length: 38085328896
Max_data_length: 0
Index_length: 0
Data_free: 4194304
Auto_increment: 21495809
Create_time: 2019-07-30 01:35:27
Update_time: NULL
Check_time: NULL
Collation: utf8_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.02 sec)
查询SQL:
SELECT COUNT(*) FROM pq_test;
- 不使用并行查询的EXPLAIN输出如下:
mysql> SET max_parallel_degree=0; EXPLAIN SELECT COUNT(*) FROM pq_test\G Query OK, 0 rows affected (0.02 sec) *************************** 1. row *************************** Id: 1 Select_type: SIMPLE Table: pq_test Partitions: NULL Type: index Possible_keys: NULL Key: PRIMARY Key_len: 8 Ref: NULL Rows: 20064988 Filtered: 100.00 Extra: Using index 1 row in set, 1 warning (0.03 sec)
- 使用并行查询的EXPLAIN输出如下:
mysql> EXPLAIN SELECT COUNT(*) FROM pq_test\G *************************** 1. row *************************** Id: 1 Select_type: SIMPLE Table: <gather2> Partitions: NULL Type: ALL Possible_keys: NULL Key: NULL Key_len: NULL Ref: NULL Rows: 20064988 Filtered: 100.00 Extra: NULL *************************** 2. row *************************** Id: 2 Select_type: SIMPLE Table: pq_test Partitions: NULL Type: index Possible_keys: NULL Key: PRIMARY Key_len: 8 Ref: NULL Rows: 10032494 Filtered: 100.00 Extra: Parallel scan (2 workers); Using index 2 rows in set, 1 warning (0.00 sec)
从该EXPLAIN可以看到,并行计划中包含Gather操作,该操作负责汇总所有Worker返回的中间结果。另外,从执行计划输出的Extra信息中看到:pq_test表使用了Parallel scan(并行扫描),期望用2个Workers来并行执行。
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。
评论