LEADING提示可精准控制嵌套查询连接顺序,但必须紧贴目标SELECT后、正确指定查询块名(如@qb_inner)和表别名,否则因作用域错误或命名不匹配而失效。

嵌套查询中优化器常因估算偏差选错驱动表,导致全表扫描或嵌套循环爆炸;用 LEADING + 查询块名可精准控制连接顺序,但必须写对位置和作用域。
LEADING 提示必须紧跟在对应 SELECT 后,且需明确指定查询块
嵌套查询(如 SELECT ... FROM (SELECT ...) t1, t2)会生成多个查询块,LEADING 默认只作用于当前块。若想让外层驱动内层结果,得显式标注查询块名:
-
LEADING必须放在目标SELECT关键字正后方,不能换行、不能加空格,例如:SELECT/*+ LEADING(t1 t2) */,而不是SELECT /*+ LEADING(t1 t2) */(中间有空格就失效) - 嵌套子查询的查询块名按出现顺序编号:最外层是
sel_1,第一个子查询是sel_2,第二个是sel_3;可用EXPLAIN查看实际命名 - 若要让子查询先执行再被外层驱动,需在子查询的
SELECT后加/*+ QB_NAME(qb_inner) */,再在外层LEADING中引用:/*+ LEADING(@qb_inner t1@qb_inner t2) */
常见失效原因:表别名未对齐或跨块引用错误
嵌套结构里同名表可能出现在不同查询块,LEADING(t1, t2) 若不带块限定,优化器可能绑定到错误的 t1(比如绑到 sel_2 里的 t1 而非 sel_1 的):
- 子查询中定义的别名(如
(SELECT * FROM orders o) o1)在外部无法直接用o,必须用o1;LEADING参数中的表名/别名必须与该查询块中实际可见的完全一致 - 若子查询用了
WITH,其内部表默认不在外层查询块可见,LEADING无法跨WITH引用——此时应改用MATERIALIZE+NO_MERGE固化结果,再对外层结果集驱动 - MySQL 8.0+ 和 TiDB 支持
@query_block_name语法,Oracle 则用@qb_name;拼错块名或漏掉@符号,Hint 会被静默忽略
配合 USE_NL 或 USE_HASH 才能真正锁定连接算法
LEADING 只控制驱动顺序,不决定连接方式;若不搭配连接算法提示,优化器仍可能在小表驱动大表时选错哈希连接或排序合并:
- 当驱动表结果集很小(USE_NL:
/*+ LEADING(t1) USE_NL(t2) */ - 两表都大且内存充足,强制哈希连接更稳:
/*+ LEADING(t1) USE_HASH(t2) */;注意 TiDB 中USE_HASH参数只能是被驱动表 - Oracle 中若被驱动表无合适索引,
USE_NL可能退化为全表扫描,此时应同步加INDEX提示指向具体索引,例如:/*+ LEADING(t1) USE_NL(t2) INDEX(t2 idx_status_time) */
嵌套查询的 Hint 生效边界极窄——位置偏移一位、块名少个 @、别名大小写不一致,都会让整个提示失效且不报错;调试时务必用 EXPLAIN 对比加 Hint 前后的计划,再用 SHOW WARNINGS(MySQL/TiDB)或 DBMS_XPLAN(Oracle)确认是否被识别。










