NO_DECORRELATE不生效,join 不走索引下推

一个好的问题描述有利于社区小伙伴更快帮你定位到问题,高效解决你的问题

【TiDB 使用环境】生产环境
【TiDB 版本】7.1
【部署方式】云上部署
【操作系统/CPU 架构/芯片详情】
【机器部署详情】CPU大小/内存大小/磁盘大小
【集群数据量】
【集群节点数】
【问题复现路径】做过哪些操作出现的问题
【遇到的问题:问题现象及影响】

select
    /*+ INL_JOIN(a) */
    * from (
    select ID,CRAD from table_a ) a 
left join (
 select   /*+ NO_DECORRELATE() */  ID,
count(1) cn from table_b group by ID
)b on a.ID=b.ID
where a.CRAD='123'

【资源配置】进入到 TiDB Dashboard -集群信息 (Cluster Info) -主机(Hosts) 截图此页面
【复制黏贴 ERROR 报错的日志】
【其他附件:截图/日志/监控】

NO_DECORRELATE() 提示优化器不要尝试解除指定查询块中对应子查询的关联。该 Hint 适用于包含关联列的
EXISTS、 IN、 ANY、 ALL、 SOME 和标量子查询,即关联子查询。

/*+ NO_DECORRELATE() */

  • 优化器可能试图将 b 子查询中的 GROUP BY ID 提前执行(变成物化临时表)
  • 但如果 b 被物化为临时表,临时表上没有索引 → 无法用于 INLJ 的 inner side
  • 导致即使 table_b.ID 有索引,也用不上

group by就是会全表少

INLjoin这种hint还真没有用过

是不是索引建的有问题

这种场景很常用呀,怎么才能走索引呢

索引OK的,没问题

咋改呢

如何才能索引下推呢

当查询的 WHERE 条件中包含可以被索引覆盖的列时,TiDB 优化器会将这部分过滤逻辑 “推” 给 TiKV。TiKV 在扫描索引时就直接过滤掉不满足条件的数据,只把符合条件的结果返回给 TiDB,从而减少了无效数据的传输和后续计算。

SELECT
a.ID,
a.CRAD,
IFNULL(b.cn, 0) AS cn – 左连接补 NULL 为 0,更友好
FROM table_a a
LEFT JOIN (
– 先关联过滤后的 a.ID,再聚合,减少计算量
SELECT
b.ID,
COUNT(1) AS cn
FROM table_b b
INNER JOIN table_a a_filter ON b.ID = a_filter.ID
WHERE a_filter.CRAD = ‘123’ – 提前过滤,缩小 table_b 聚合范围
GROUP BY b.ID
) b ON a.ID = b.ID
WHERE a.CRAD = ‘123’; – 提前过滤 table_a,只取需要的行

– 给 table_a 建立覆盖索引(CRAD 过滤 + ID 关联,无需回表)
CREATE INDEX idx_table_a_crad_id ON table_a (CRAD, ID);

– 给 table_b 建立分组/关联的索引(加速 COUNT 聚合)
CREATE INDEX idx_table_b_id ON table_b (ID);

没用过你发的这种索引

card列的索引有用到,你直接把a、b连接后分组试试呢?查询结果应该一样吧