
有个很简单的查询,唯一的问题是数据表较大,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 221 天前 via Android B 表取的字段全加索引上试试呢? |
2 winoros 221 天前 via Android 最好把 explain 的结果完整的贴一下,可以把表名之类得遮掉。现在这些信息不太能判断问题 |
4 Sidney 221 天前 可以先确认一下 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 220 天前 via Android 这个看起来是估算的问题 A 表的估算是三百万行,这个表是刚刚被 analyze 过吗,如果不是的话可以看一下这个表上次 analyze 的时间 |
8 spkinger 220 天前 盲猜下,换掉不等查询,B.ip !="" 换成 B.ip > "" 试试? |
9 Defined 220 天前 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 220 天前 |
11 winoros 220 天前 @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 |