tencent cloud

TDSQL Boundless

产品动态
产品简介
产品概述
应用场景
产品架构
实例类型
兼容性说明
自研内核
内核概述
内核版本更新动态
功能类特性
性能类特性
产品计费
计费概述
购买方式
价格详情
续费说明
欠费说明
退费说明
快速入门
创建实例
连接实例
用户指南
数据迁移
数据同步/订阅
实例管理
配置变更
参数配置
账号管理
安全组
备份与恢复
数据库审计
标签管理
实践教程
Online DDL 的技术演进与使用实践
锁机制解析与问题排查实践
数据智能调度及相关性能优化实践
TDSQL Boundless 选型指南与实践教程
开发指南
开发指南(MySQL 兼容模式)
开发指南(HBase 兼容模式)
性能调优
性能调优概述
SQL 调优
DDL 调优
性能白皮书
性能概述
TPC-C 测试
Sysbench 测试
API 文档
History
Introduction
API Category
Making API Requests
Instance APIs
Security Group APIs
Task APIs
Backup APIs
Rollback APIs
Parameter APIs
Database APIs
Data Types
Error Codes
通用参考
系统原理
SQL 参考
数据库参数说明
TPC-H 基准测试数据模型参考
错误码信息
安全与合规
常见问题
服务协议
服务等级协议
服务条款
隐私政策
数据处理和安全协议
联系我们
词汇表

优化器 Hints

PDF
聚焦模式
字号
最后更新时间: 2026-03-06 18:50:07

概述

TDSQL 在兼容 MySQL 官方 Hint 标准的基础上,针对分布式并行执行特性扩展了专门的并行 Hint。这些 Hint 主要用于优化器指导,帮助用户更精细地控制查询的并行执行策略,提升复杂查询的性能。

PARALLEL/NO_PARALLEL Hint 并行度控制

可以使用 PARALLEL Hint 指定进行 Parallel Scan 的表和它的并行度。语法如下:

PARALLEL Hint 是一个3个层级的 Hint Global、Query Block 和 Table 级别,举例说明:
PARALLEL(num) -- Global级、Query Block级
PARALLEL(@qbname num) -- Query Block级
PARALLEL(tablename) -- Table 级
PARALLEL(tablename num) -- Table 级
NO_PARALLEL -- Global级、Query Block级
NO_PARALLEL(@qbname) -- Query Block级
NO_PARALLEL(tablename) -- Table 级
其中,NO_PARALLEL 是禁止并行,tablename 和 qbname 的语法请参考 MySQL 官方文档。
Global 级:当在主查询中指定,没有给定 query block name 和 table name 时。这时 num 将作为整个查询的默认并行度,子查询还可以通过自己的PARALLEL Hint 来覆盖它。
Query Block 级:当在非主查询中指定,或者给定了 query block name,但没有给定 table name 时。这时 num 将作为这个子查询的默认并行度,可以被表级的覆盖。
Table 级:当在 Hint 中给定了表名时。如果只给表名没给 num,会向上(即:Query Block、Table 级别、max_parallel_degree 变量)确定并行度,如果最后没有拿到并行度,即到 max_parallel_degree 时该值为0,则不会并行。另外,我们可以支持指定多个表并行,将来的计划中会支持多个表并行。
这里 Query Block 级和 Global 级(当 Query Block 级未指定时)是可以当前决定当前 Query Block 是否使用并行计划的,如当它被指定了 NO_PARALLEL 时那么当时 Query Block 就不会进入并行优化阶段,而表级别只影响当前表是否进行并行扫描,也就是说如果 Query Block 和 Global 级别未指定 Hint,而当前的 max_parallel_degree 大于0,即使所有表都使用了 NO_PARALLEL,并行优化器还是会找出一个并行扫描表来并行执行。
针对 PARALLEL Hint 的语法,显示一些用法如下:
-- Global 级别
EXPLAIN select /*+ PARALLEL(4) */ * from t1 where a > 4;

-- Query block 级别,只在最顶层查询起作用
EXPLAIN select /*+ QB_NAME(q1) PARALLEL(@q1 4) */ * from t1 where a > 4;

-- Query block 级别,只在子查询中有效
explain select * from t3 where a = (select /*+ PARALLEL(2) */ count(a) from t3);

-- Table 级别
EXPLAIN select /*+ PARALLEL(t1 4) */ from t1 where a > 4;

-- Table 级别
EXPLAIN select /*+ PARALLEL(t3@q2 4) */ * from t3 where a = (select /*+ QB_NAME(q2) */ count(a) from t3);

-- Table 级别
EXPLAIN select /*+ PARALLEL(@q2 t3 4) */ * from t3 where a = (select /*+ QB_NAME(q2) */ count(a) from t3);

PQ_DISTRIBUTE Hint 数据分布策略

用于指示优化器如何在查询计划中添加数据重分布操作。语法如下:

-- 基本语法
PQ_DISTRIBUTE(tablespec strategy1 strategy2)
PQ_DISTRIBUTE(tablespec strategy)

-- 针对特定操作类型
PQ_DISTRIBUTE(target strategy1 strategy2)
target :操作目标,支持 AGGREGATE、SORT 和 WINDOW,分别指定 GROUP BY,ORDER BY, WINDOW 函数的分布策略,WINDOW 可以在后面指定 WINDOW 的名字。
strategy1strategy2:重分布的策略,支持 NONE、GATHER、HASH、BROADCAST。

JOIN 操作分布策略

PQ_DISTRIBUTE(t1 HASH, HASH)PQ_DISTRIBUTE(t1@qb1 HASH, HASH) PQ_DISTRIBUTE(@qb1 t1 HASH HASH):指定 t1 和它前一个表做 JOIN 时,先使用 HASH 重分布,再在各个节点上做 JOIN。
PQ_DISTRIBUTE(t1 BROADCAST, NONE):指定 t1 和它前一个表做 JOIN 时,前一个也就是外表做 Broadcast,再和 t1 做 JOIN。
PQ_DISTRIBUTE(t1 GATHER):指定 t1 表先做 Gather,再和其他表做 JOIN。
使用示例:
-- 两个表都进行 HASH 重分布后 JOIN
SELECT /*+ PQ_DISTRIBUTE(t1 HASH, HASH) */ *
FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id;

-- 外表广播,内表不重分布
SELECT /*+ PQ_DISTRIBUTE(t1 BROADCAST, NONE) */ *
FROM small_table t1 JOIN large_table t2 ON t1.id = t2.id;

-- 表数据收集到 Leader 后执行 JOIN
SELECT /*+ PQ_DISTRIBUTE(t1 GATHER) */ *
FROM table1 t1 JOIN table2 t2 ON t1.id = t2.id;

GROUP BY 聚合分布策略

并行 GROUP BY 操作最多会执行二阶段,这里第1个策略表示是第一阶段 GROUP BY 之前的数据分发操作,第2个则表示第二阶段之前的数据分发操作,如果只有一个策略则表示是一阶段。
PQ_DISTRIBUTE(AGGREGATE NONE):完全下推一阶段。
PQ_DISTRIBUTE(AGGREGATE NONE, GATHER):Worker 和 Leader 二阶段。
PQ_DISTRIBUTE(AGGREGATE NONE HASH):Worker 和 Worker 二阶段。
PQ_DISTRIBUTE(AGGREGATE GATHER):只在 Leader 上的一阶段。
使用示例:
-- 完全下推的一阶段聚合
SELECT /*+ PQ_DISTRIBUTE(AGGREGATE NONE) */
department, AVG(salary)
FROM employees
GROUP BY department;

-- Worker 和 Leader 二阶段聚合
SELECT /*+ PQ_DISTRIBUTE(AGGREGATE NONE, GATHER) */
department, AVG(salary)
FROM employees
GROUP BY department;

-- Worker 和 Worker 二阶段聚合
SELECT /*+ PQ_DISTRIBUTE(AGGREGATE NONE HASH) */
department, AVG(salary)
FROM employees
GROUP BY department;

-- 只在 Leader 上执行的一阶段聚合
SELECT /*+ PQ_DISTRIBUTE(AGGREGATE GATHER) */
department, AVG(salary)
FROM employees
GROUP BY department;

ORDER BY 排序分布策略

PQ_DISTRIBUTE(SORT NONE, GATHER):Worker + Leader 的 Merge Sort。
PQ_DISTRIBUTE(SORT GATHER):只在 Leader 上做 Sort。
使用示例:
-- Worker 局部排序 + Leader 归并排序
SELECT /*+ PQ_DISTRIBUTE(SORT NONE, GATHER) */ *
FROM large_table
ORDER BY create_time DESC;

-- 只在 Leader 上全局排序
SELECT /*+ PQ_DISTRIBUTE(SORT GATHER) */ *
FROM large_table
ORDER BY create_time DESC;

WINDOW 函数分布策略

PQ_DISTRIBUTE(WINDOW GATHER)

策略说明: 将窗口函数计算完全集中在 Leader 节点执行。所有数据先收集到 Leader 节点,然后在单节点上执行窗口函数计算。
适用场景:
数据量相对较小,可以单节点处理
需要全局排序的窗口函数(如 RANK() OVER (ORDER BY ...))
窗口函数分区数较少,无法有效并行化
示例:
-- 在 Leader 节点上计算全局排名
SELECT /*+ PQ_DISTRIBUTE(WINDOW GATHER) */
student_id,
score,
RANK() OVER (ORDER BY score DESC) as global_rank
FROM exam_scores;

-- 计算每个学生的成绩变化趋势(数据量较小)
SELECT /*+ PQ_DISTRIBUTE(WINDOW GATHER) */
student_id,
exam_date,
score,
LAG(score) OVER (PARTITION BY student_id ORDER BY exam_date) as prev_score
FROM student_scores;

PQ_DISTRIBUTE(WINDOW HASH)

策略说明: 按照窗口函数的 PARTITION BY 子句的列进行哈希分布,在各个 Worker 节点上并行执行窗口函数计算。
适用场景:
数据量较大,需要并行处理
窗口函数有明确的分区键,且分区数据分布均匀
每个分区内的数据量适中,适合并行计算
示例:
-- 按学科分区并行计算排名
SELECT /*+ PQ_DISTRIBUTE(WINDOW HASH) */
subject,
student_id,
score,
RANK() OVER (PARTITION BY subject ORDER BY score DESC) as subject_rank
FROM exam_scores;

-- 按部门分区计算工资累计总和
SELECT /*+ PQ_DISTRIBUTE(WINDOW HASH) */
department,
employee_id,
salary,
SUM(salary) OVER (PARTITION BY department ORDER BY hire_date) as cumulative_salary
FROM employees;

PQ_DISTRIBUTE(WINDOW win1 GATHER)

策略说明: 针对特定命名的窗口(使用 WINDOW 子句定义)采用 GATHER 策略执行。
适用场景:
查询中包含多个窗口函数,需要对特定窗口采用不同策略
命名的窗口函数需要特殊处理
混合使用不同分布策略优化复杂查询
示例:
-- 为特定命名的窗口使用GATHER策略
SELECT /*+ PQ_DISTRIBUTE(WINDOW win1 GATHER) */
student_id,
subject,
score,
AVG(score) OVER win1 as avg_score,
RANK() OVER (PARTITION BY subject ORDER BY score DESC) as rank
FROM exam_scores
WINDOW win1 AS (PARTITION BY student_id);

-- 多个命名窗口的不同策略
SELECT /*+ PQ_DISTRIBUTE(WINDOW win1 GATHER) PQ_DISTRIBUTE(WINDOW win2 HASH) */
department,
employee_id,
salary,
AVG(salary) OVER win1 as dept_avg,
SUM(salary) OVER win2 as running_total
FROM employees
WINDOW win1 AS (PARTITION BY department),
win2 AS (PARTITION BY department ORDER BY hire_date);

PQ_DISTRIBUTE(WINDOW win1 HASH)

策略说明: 针对特定命名的窗口采用 HASH 分布策略并行执行。
适用场景:
特定命名的窗口函数数据量较大,需要并行优化
不同窗口函数需要采用不同的并行策略
精细化控制复杂查询的执行计划
示例:
-- 为特定窗口使用 HASH 分布
SELECT /*+ PQ_DISTRIBUTE(WINDOW win1 HASH) */
product_category,
product_id,
sales_amount,
SUM(sales_amount) OVER win1 as category_total,
RANK() OVER (ORDER BY sales_amount DESC) as global_rank
FROM sales_data
WINDOW win1 AS (PARTITION BY product_category);

-- 混合策略:一个窗口 GATHER,另一个窗口 HASH
SELECT /*+ PQ_DISTRIBUTE(WINDOW win1 GATHER) PQ_DISTRIBUTE(WINDOW win2 HASH) */
customer_id,
order_date,
amount,
AVG(amount) OVER win1 as cust_avg, -- 小数据量用GATHER
SUM(amount) OVER win2 as running_sum -- 大数据量用HASH
FROM orders
WINDOW win1 AS (PARTITION BY customer_id),
win2 AS (PARTITION BY customer_id ORDER BY order_date);

SUBQUERY Hint 子查询并行策略

并行查询 MySQL SUBQUERY Hint 增加了2个并行相关的策略(strategy),这些策略可以和 MySQL 原来的策略混合使用。
PQ_PRE_EVALUATION:指定子查询在引用它的父查询执行之前先提前执行,并行 Worker 之间直接读取子查询结果。
PQ_INLINE_EVALUATION:强制不提前执行子查询,也就是按 MySQL 的逻辑根据父查询的需要按需执行。
示例:
-- 指定这个 IN 子查询使用 MATERIALIZATION 策略并且在并行计划不使用预先执行策略
EXPLAIN FORMAT=TREE
SELECT * FROM t1
WHERE t1.a IN (
SELECT /*+ SUBQUERY(MATERIALIZATION, PQ_INLINE_EVALUATION) */ a
FROM t2
);

-- 指定 Derived Table 子查询 t 使用预先执行策略
EXPLAIN FORMAT=TREE
SELECT /*+ NO_MERGE(t) pq_distribute(t1 none) */ t1.a
FROM t1, (
SELECT /*+ subquery(pq_inline_evaluation) */ a
FROM t2
) t
WHERE t1.a = t.a;

帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈