indexMerge不起效果

为提高效率,请提供以下信息,问题描述清晰能够更快得到解决:
【 TiDB 使用环境】
v5.2.1

【概述】 场景 + 问题概述

设置过2个参数
set global tidb_analyze_version = 1
set global tidb_enable_index_merge = 1;
并且tidb和服务器都重启过
在navicat里执行以下sql
SELECT
*
FROM
score_account_balance_day
WHERE
(
_id = ‘6112781271fd5200017b0c15’
OR ti_id = 2719232
);
执行速度很快,并且能走上indexmerage,并且不会走到tiflash
但是在java里执行时会有几率(刚重启完服务器测过,是能走上索引merge的,不知道触发了什么就不行了)先走tiflash,我把tiflash关了后(replace置为0)开始走全表扫描,还是没有走indexmerage,而且在这个情况下,几乎所有的同类型sql都无法走indexmerge,截图如下




【业务影响】

【TiDB 版本】

【应用软件及版本】

【附件】 相关日志及配置信息

  • TiUP Cluster Display 信息
  • TiUP CLuster Edit config 信息

监控(https://metricstool.pingcap.com/)
tidb-online-Overview_2021-11-25T01_27_47.168Z.json (202.1 KB)


若提问为性能优化、故障排查类问题,请下载脚本运行。终端输出的打印结果,请务必全选并复制粘贴上传。

这个脚本是在哪执行的,我用tiup部署的 没有tidb-ansible这个目录

  1. 可以重新收集下统计信息试试
  2. 如果还不行,麻烦上传 explain analyze sql 的执行计划。

image


重新analyze在程序执行出来的还是一样的情况

explain analyze sql结果如下

id estRows actRows task access object execution info operator info memory disk
IndexMerge_11 2.00 1 root time:1.2ms, loops:2, index_task:{fetch_handle:967.508µs, merge:8.574µs}, table_task:{num:1, concurrency:5, fetch_row:627.646µs, wait_time:539.31µs} N/A N/A
├─IndexRangeScan_8(Build) 1.00 1 cop[tikv] table:community_integral_summary_day, index:id(_id) time:498.6µs, loops:1, cop_task: {num: 1, max: 453µs, proc_keys: 1, rpc_num: 1, rpc_time: 440.9µs, copr_cache_hit_ratio: 0.00}, tikv_task:{time:0s, loops:1}, scan_detail: {total_process_keys: 1, total_keys: 1, rocksdb: {delete_skipped_count: 0, key_skipped_count: 0, block: {cache_hit_count: 7, read_count: 0, read_byte: 0 Bytes}}} range:[“5fcb5cc4a2608c62caf6028c”,“5fcb5cc4a2608c62caf6028c”], keep order:false N/A N/A
├─TableRangeScan_9(Build) 1.00 1 cop[tikv] table:community_integral_summary_day time:470.3µs, loops:1, cop_task: {num: 1, max: 427.2µs, proc_keys: 1, rpc_num: 1, rpc_time: 420µs, copr_cache_hit_ratio: 0.00}, tikv_task:{time:0s, loops:1}, scan_detail: {total_process_keys: 1, total_keys: 1, rocksdb: {delete_skipped_count: 0, key_skipped_count: 0, block: {cache_hit_count: 7, read_count: 0, read_byte: 0 Bytes}}} range:[1463539616955311190,1463539616955311190], keep order:false 210 Bytes N/A
└─TableRowIDScan_10(Probe) 2.00 1 cop[tikv] table:community_integral_summary_day time:538.6µs, loops:2, cop_task: {num: 1, max: 487.4µs, proc_keys: 1, rpc_num: 1, rpc_time: 481.5µs, copr_cache_hit_ratio: 0.00}, tikv_task:{time:0s, loops:1}, scan_detail: {total_process_keys: 1, total_keys: 1, rocksdb: {delete_skipped_count: 0, key_skipped_count: 0, block: {cache_hit_count: 7, read_count: 0, read_byte: 0 Bytes}}} keep order:false N/A N/A

现在很诡异的是代码里跑的sql用不上merge 但是navicat里的就可以

show variables like ‘tidb_enable_index_merge’;
navicat里 show 下看看是不是 1

是的 而且我连了其他的tidb-server出来的结果都是1

  1. 你发的执行计划是走的 indexmerge 吧
  2. 检查下代码里有使用 hint 吗?

是的 navicat里是可以走indexmerge的 代码里没有特殊指定hint

  1. 找到java执行不走 indexmerge 的 tidb-server。 客户端连接这个同一个tidb-server物理ip,别连接负载均衡。试试看。
  2. 如果只连接一个 tidb-server ,java 和 客户端不一样,尝试打开 general log ,反馈下 general log 的日志。
  3. 目前可以考虑先加 hint 或者 sql bind 绑定执行计划。

1:试过了,客户端直连一个tidb-server的物理ip同样可以indexmerge,就很奇怪
2:这是我开了general log后根据表名搜出来的日志,麻烦看下信息是不是收集全了
logs (1).zip (36.9 KB)

查询语句如下

SELECT
  *
FROM
  community_integral_summary_day
WHERE
  (
    _id = '60724340054b731d194a4423'
    OR ti_id = 1463689021494739747
  );

兄弟,我是程序侧的SQL不按照SPM走,navicat或者mysql shell client执行就可以。
感觉异曲同工。

哈哈 不知道啥情况的诡异bug 我还没试SPM ,而且我用mysql shell client也是可以走上索引的

  1. 表结构方便上传下吗?
  2. 从日志看,好像每次查询前,都有一个 update 操作? 这里 update 和 select 具体是什么逻辑顺序? 在 java 代码里。 有可能模拟客户端和java侧相同的操作顺序和时间控制吗? update 后 select 。但是看起来时间差非常小。
    [2021/11/25 13:41:02.391 +08:00] [Info] [session.go:2974] [GENERAL_LOG] [conn=2311] [user=score_mongo_online_wr@192.168.10.46] [schemaVersion=3676] [txnStartTS=0] [forUpdateTS=0] [isReadConsistency=false] [current_db=score_mongo_online] [txn_mode=PESSIMISTIC] [sql=“UPDATE community_integral_summary_day SET FF0001_1 = FF0001_1 +108,FF0001_2 = FF0001_2 +0 WHERE ( _id = ‘5ff96fd2a2608c62cafcfdae’ OR ti_id = 13528467 )”]
    [2021/11/25 13:41:02.396 +08:00] [Info] [session.go:2974] [GENERAL_LOG] [conn=2311] [user=score_mongo_online_wr@192.168.10.46] [schemaVersion=3676] [txnStartTS=429344387851091981] [forUpdateTS=429344387864461313] [isReadConsistency=false] [current_db=score_mongo_online] [txn_mode=PESSIMISTIC] [sql=“SELECT * FROM community_integral_summary_day WHERE ( _id = ‘5ff96fd2a2608c62cafcfdae’ OR ti_id = 13528467 )”]
  3. 另外慢日志找一下这个时间段,发一下这个查询结果的慢日志,需要确认下,这个sql是没有走 indexmerge,多谢。

表结构:
new 17.txt (4.3 KB)

业务的确是每次更新后会有一次一模一样条件的查询请求去获取更新后的记录,为什么会这样解释起来有点复杂…,我在nacivat直接把两个语句摆在一起执行了下,看这个执行的速度肯定是用上了indexmerge的

慢日志截图:

我们先分析下,麻烦你先把general log 关闭吧,多谢。

请问是在事务里执行的吗? update 和 select 相同的条件

是的 我在navicat手动开启事务试了下 能复现 但是不是100%复现,而且基本都很快 只有个别几次慢
执行select用了2s


执行select很快

  1. 现在 IndexMerge 不支持在有写操作的事务里面使用。 https://github.com/pingcap/tidb/pull/29875 所以当前这种暂时没法在事务里使用 indexmerge。
    Problem Summary: We need UnionScan to read dirty buffer when we got write operation in transaction. But there is no implementation for IndexMergeReader to scan buffer. So we disable the usage of IndexMerge in this situation. So we need to implement memIndexMergeReader just like memIndexLookupReader
  2. 第二次执行快,应该是因为有缓存了。
  3. 目前 workaround ,可以考虑用 ti_id 这个索引(或者试试其他索引)能不能快一些,不使用 indexmerge

如果不开启indexmerge直接使用or的话是没法使用索引的,我想办法从业务角度解决把

看这个pr的意思是提交者已经解决了这个问题在等待代码合并进master吗

最后谢谢答复!

PR 看起来还需要 review 状态,可以多关注一下这个 PR。