有个很简单的查询,唯一的问题是数据表较大,A 有千万级,B 有接近十亿
SELECT FIELDS FROM A
LEFT JOIN B ON A.a=B.b
WHERE A.w="" AND A.time>?
A 表在 time 上有索引,B 表在 b 上有索引
在我开发环境的 MySQL 中,explain 看上去一切正常
A range time
B ref idx_b
但是到了线上的 TIDB 中,就变成了
IndexRangeScan_101(Build) table:A ,index:idx_time(time)
TableFullScan_114 table:B keep order:false
主要的问题是,B 变成了全表扫描,完全无法接受。
如果像 MySQL 正常索引,A 表过滤后的数据量只有几千条。
改了 USE INDEX 以后,变成了索引全扫描?情况也没好到哪里去...
Analyze Table 的命令也执行过了,还是没变化
IndexRangeScan_101(Build) table:A ,index:idx_time(time)
IndexFullScan table:B, index:idx_b(b) keep order:false
![]() |
1
wuxianliang 1 天前 via Android
B 表取的字段全加索引上试试呢?
|
![]() |
2
winoros 1 天前 via Android
最好把 explain 的结果完整的贴一下,可以把表名之类得遮掉。现在这些信息不太能判断问题
|
![]() |
4
Sidney 1 天前
可以先确认一下 A.a = B.b, 这两个列的类型是不是一致的,有没有类型转换
|
![]() |
5
pkoukk OP @winoros
替换了表名的 explain 结果,另外上面给的 SQL 有一点小偏差,不过应该也能从 explain 中看出来。 实际是类似于 SELECT FIELDS FROM A LEFT JOIN B ON A.a=B.b AND B.type="realease" AND B.ip !="" WHERE A.w="" AND A.time>? ``` Projection_7 35303209.48 root B.ip, A.ip_id, A.is_deleted, A.insert_time, A.delete_time └─HashJoin_26 35303209.48 root left outer join, equal:[eq(A.ip_id, B.ip_id)] ├─IndexLookUp_47(Build) 2933525.58 root │ ├─IndexRangeScan_44(Build) 3106246.80 cop[tikv] table:A, index:idx_delete_time(delete_time) range:[1740758400,+inf], keep order:false │ └─Selection_46(Probe) 2933525.58 cop[tikv] eq(A.is_deleted, 1), lt(A.insert_time, 1743436800) │ └─TableRowIDScan_45 3106246.80 cop[tikv] table:A keep order:false └─TableReader_50(Probe) 35303209.48 root data:Selection_49 └─Selection_49 35303209.48 cop[tikv] eq(B.type, "release"), ne(B.ip, ""), not(isnull(B.ip_id)) └─TableFullScan_48 1163701770.00 cop[tikv] table:B keep order:false ``` |
![]() |
6
winoros 1 天前 via Android
这个看起来是估算的问题 A 表的估算是三百万行,这个表是刚刚被 analyze 过吗,如果不是的话可以看一下这个表上次 analyze 的时间
|
![]() |
8
spkinger 1 天前
盲猜下,换掉不等查询,B.ip !="" 换成 B.ip > "" 试试?
|
9
Defined 1 天前
B 表要走 ip_id 相关的 index 的话 join 需要时 index join ,可以加 hint 试下,但这个数量级用 index join 不一定比 hash join 快。
hint 参考 EXPLAIN ANALYZE SELECT /*+ INL_JOIN(t1, t2) */ * FROM t1 INNER JOIN t2 ON t1.id = t2.t1_id WHERE t1.int_col = 1; |
![]() |
10
winoros 1 天前
|
![]() |
11
winoros 1 天前
@winoros https://docs.pingcap.com/zh/tidb/stable/sql-plan-management/
和 binding 来控制执行计划 可以的话可以看一下 delete_time > 1740758400 的 [explain analyze]( https://docs.pingcap.com/zh/tidb/stable/sql-statement-explain-analyze/#explain-analyze)(估算行数和真实执行行数)是否接近 以及单独只有 insert_time > 1743436800 的 explain analyze |