OR条件为何不走索引合并??

【 TiDB 使用环境】生产环境
【 TiDB 版本】 v6.1
【遇到的问题:问题现象及影响】

当使用 select … from a join b on a.主键 = b.唯一建 where a.time >= xxx OR b.time >= xxx 的时候(time 都是索引),速度很慢,看了explain计划,没有用到索引合并?

具体的sql如下:

SELECT
	a.uid,
CASE
		WHEN a.reg_area IN ( 111, 0 ) THEN
		b.quyubh ELSE a.reg_area 
	END reg_area,
CASE
		WHEN location_area = 0 
		AND REGIONCODE IS NOT NULL THEN
			REGIONCODE ELSE a.location_area 
		END location_area 
FROM
	`dwd`.`user_extend` a
	JOIN `dwd`.`user_first_location` b ON b.zhanghao = a.uid 
WHERE
	a.update_time >= '2023-03-06 00:00:00' OR b.update_time >= '2023-03-06 00:00:00' ;

【附件:截图/日志/监控】

OR 的情况下,执行计划如下:

Projection_9	19376062.00	root		dwd.user_extend.uid, case(in(dwd.user_extend.reg_area, 912000000041844186, 0), dwd.user_first_location.quyubh, dwd.user_extend.reg_area)->Column#84, case(and(eq(dwd.user_extend.location_area, 0), not(isnull(dwd.user_first_location.regioncode))), dwd.user_first_location.regioncode, dwd.user_extend.location_area)->Column#85
└─Projection_10	19376062.00	root		dwd.user_extend.uid, dwd.user_extend.reg_area, dwd.user_extend.location_area, dwd.user_first_location.quyubh, dwd.user_first_location.regioncode
  └─IndexJoin_16	19376062.00	root		inner join, inner:TableReader_13, outer key:dwd.user_first_location.weimaihao, inner key:dwd.user_extend.uid, equal cond:eq(dwd.user_first_location.weimaihao, dwd.user_extend.uid), other cond:or(ge(dwd.user_extend.update_time, 2023-03-06 00:00:00.000000), ge(dwd.user_first_location.update_time, 2023-03-06 00:00:00.000000))
    ├─TableReader_45(Build)	19376062.00	root		data:Selection_44
    │ └─Selection_44	19376062.00	cop[tikv]		not(isnull(dwd.user_first_location.weimaihao))
    │   └─TableFullScan_43	19398524.00	cop[tikv]	table:b	keep order:false
    └─TableReader_13(Probe)	1.00	root		data:TableRangeScan_12
      └─TableRangeScan_12	1.00	cop[tikv]	table:a	range: decided by [dwd.user_first_location.weimaihao], keep order:false

其他说明:

  1. on 条件左右都是主键/唯一建, update_time 都是索引。
  2. 如果我把 OR 拆开,分别查询 a.update_time >= xx 以及b.update_time >= xx, 那就都是几秒搞定
  3. OR 条件一加上,就超过1分钟了
  4. 两个表都是千万级别的表

你用or条件肯定是没办法先走索引的啊,如果先走了索引,过滤掉的值,能被关联到怎么办?所以肯定是先把两个表全表扫了,然后再过滤,后面过滤肯定走不了索引的

所以,索引合并 的前提条件是一张表的OR查询条件吗? 多表关联下 就不会执行两个表索引合并了 是吗?

改成先过滤,这样索引就生效了,在聚合就好了,范围小就会更快了

你改成and就能过滤了,两表关联后or条件过滤肯定用不上索引合并的

改用IN where a.update_time in (‘2023-03-06 00:00:00’,‘2023-03-06 00:00:00’)

嗯? 没看懂。。

and 那肯定可以走索引了,那看来连表查询就是用不了 索引合并吧

改了几次 感觉结果都不对。。请问下,怎么改? 我sql不太会 :joy:

是直接把OR 拆了,然后写成两个sql 加一个union 吗? 好像结果对了,也各自用索引了。 是这么改吗?

同一张表的or的话如果or前后都有索引应该是可以使用到index_merge 的,多表关联的话应该用不上

可以试试看看 index merge
https://docs.pingcap.com/zh/tidb/stable/explain-index-merge

试过了,没用,索引合并应该只对 单表适用

对,我试起来 感觉的确是单表可用 索引合并

这样做就行了,已测,对~

此话题已在最后回复的 60 天后被自动关闭。不再允许新回复。