select for update实际执行未命中索引,使用了FORCE INDEX 也没有走到索引上

【 TiDB 使用环境】生产环境
【 TiDB 版本】5.0.5
【复现路径】select for update
【遇到的问题:问题现象及影响】dashboard上显示了执行计划,并且使用了force index,仍然没有走到索引上,导致锁表10s左右,频繁出现这个问题
【资源配置】高性能服务器
【附件:截图/日志/监控】
实际执行效果显示没走到索引上

表结构:

CREATE TABLE `lp` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `account_id` bigint(20) NOT NULL,
  `seg_t` varchar(10) NOT NULL DEFAULT 'CCC',
  `type` varchar(1) NOT NULL,
  `stock` bigint(20) NOT NULL,
  `m` varchar(10) NOT NULL DEFAULT 'UUU',
  `sec_t` varchar(10) NOT NULL DEFAULT 'TKTK',
  `q` double NOT NULL,
  `d_q` decimal(30, 10) NOT NULL DEFAULT '0.0000000000',
  `a_c` decimal(30, 10) DEFAULT NULL,
  `l_o_a` datetime DEFAULT NULL,
  `business_from` date NOT NULL,
  `business_to` date NOT NULL,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `lp_unique_key` (
    `account_id`,
    `stock`,
    `business_to`,
    `type`
  ),
  KEY `idx_lp_from_date` (`business_from`),
  KEY `IDX_LEDGER_POSITION_STOCK_ID_DATE` (`stock`, `business_to`),
  KEY `idx_lp_account_date` (`account_id`, `business_to`)
) ENGINE = InnoDB AUTO_INCREMENT = xxxxxxxx DEFAULT CHARSET = utf8 ROW_FORMAT = DYNAMIC

执行sql语句为:

SELECT xxxxx
FROM
  lp FORCE INDEX(lp_unique_key)
WHERE
  (
    account_id = ?
    AND stock = ?
    AND `type` = ?
    AND business_to >= ?
  ) FOR
UPDATE
  [arguments: (90019329700, 30443, T, 2023-01-18 00:00:00)];```
执行计划为:
id                      	task     	estRows	operator info                                                                                                                                                                                                                        	actRows	execution info                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 	memory 	disk
SelectLock_7            	root     	0.09   	for update 0                                                                                                                                                                                                                         	2      	time:8.38s, loops:4, lock_keys: {time:663.5µs, region:1, keys:1, lock_rpc:636.761µs, rpc_count:1}                                                                                                                                                                                                                                                                                                                                                                                                            	N/A    	N/A
└─UnionScan_8           	root     	0.09   	eq(lp.lp.account_id, 9193297), eq(lp.lp.stock_id, 30443), eq(lp.lp.type, "T"), ge(lp.lp.business_to, 2023-01-18 00:00:00.000000)	2      	time:11.3ms, loops:4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           	N/A    	N/A
  └─IndexLookUp_12      	root     	0.09   	                                                                                                                                                                                                                                     	2      	time:11.3ms, loops:6, index_task: {total_time: 1.25ms, fetch_handle: 1.24ms, build: 1.44µs, wait: 4.9µs}, table_task: {total_time: 16.6ms, num: 2, concurrency: 10}                                                                                                                                                                                                                                                                                                                                          	16.5 KB	N/A
    ├─Selection_11      	cop[tikv]	0.09   	eq(lp.lp.type, "T")                                                                                                                                                                                          	2      	time:1.21ms, loops:6, cop_task: {num: 2, max: 852.4µs, min: 309.3µs, avg: 580.8µs, p95: 852.4µs, max_proc_keys: 2, p95_proc_keys: 2, rpc_num: 2, rpc_time: 1.12ms, copr_cache_hit_ratio: 0.00}, tikv_task:{proc max:0s, min:0s, p80:0s, p95:0s, iters:2, tasks:2}, scan_detail: {total_process_keys: 4, total_keys: 22, rocksdb: {delete_skipped_count: 8, key_skipped_count: 36, block: {cache_hit_count: 24, read_count: 0, read_byte: 0 Bytes}}}                                                        	N/A    	N/A
    │ └─IndexRangeScan_9	cop[tikv]	0.18   	table:lp, index:lp_unique_key(account_id, stock, business_to, type), range:[9193297 30443 2023-01-18,9193297 30443 +inf], keep order:false                                                                     	4      	tikv_task:{proc max:0s, min:0s, p80:0s, p95:0s, iters:2, tasks:2}, scan_detail: {total_process_keys: 0, total_keys: 0, rocksdb: {delete_skipped_count: 0, key_skipped_count: 0, block: {cache_hit_count: 0, read_count: 0, read_byte: 0 Bytes}}}                                                                                                                                                                                                                                                               	N/A    	N/A
    └─TableRowIDScan_10 	cop[tikv]	0.09   	lp, keep order:false                                                                                                                                                                                             	2      	time:9.57ms, loops:4, cop_task: {num: 2, max: 572µs, min: 321.1µs, avg: 446.6µs, p95: 572µs, max_proc_keys: 1, p95_proc_keys: 1, tot_proc: 1ms, rpc_num: 3, rpc_time: 1.36ms, copr_cache_hit_ratio: 0.00}, ResolveLock:{num_rpc:1, total_time:7.99ms}, tikv_task:{proc max:1ms, min:0s, p80:1ms, p95:1ms, iters:2, tasks:2}, scan_detail: {total_process_keys: 2, total_keys: 2, rocksdb: {delete_skipped_count: 0, key_skipped_count: 0, block: {cache_hit_count: 16, read_count: 0, read_byte: 0 Bytes}}}	N/A    	N/A

阶段耗时:


隔离级别是RR,可重复读

1 个赞

IndexRangeScan_9就代表使用索引了吧

  1. 如楼上所说,执行计划中显示已经使用了索引
  2. 如果是单纯的查询,为什么要加for update呢?for update 会加写锁,此时如有其他session在更改这条记录,就会出现锁等待。单纯的查询建议去掉for update
  1. 执行计划显示使用了索引,但是实际执行并未使用到索引,如图一。
  2. 业务上需要加写锁保证写数据的原子性,同时整个操作是在事务中进行的,需要加上forUpdate。写这条数据之前需要加上写锁(加锁的方式也是用问题描述中的sql加锁),所以是锁表导致的?

执行计划显示使用了索引,但是实际执行没有走索引,如图一

执行计划就是实际执行呀,语句前面加上explain analyze 就是实际执行计划,不是预计执行计划

  1. 你的执行计划是手动执行显示出来的吧。跟你截图中的sql是一个时间点的吗?
  2. 个人还是觉得尽量避免用for update这种方式,用不好的话,经常有人误锁表。可以考虑以下方式:
    begin
    XXXXX;
    XXXXXX;
    commit;

这种不能解决读锁的需求吧,

是的 要务考虑业务场景了 看是否真的需要

业务场景上需要用forUpdate保证原子性,这个以前在用mysql的时候就用了,没有这类情况。

如果实际执行的时候用到了索引,为什么监控上显示没走索引?或者走了索引那也不应该锁表吧,而是锁特定的行才对?

主要看慢查询页面上面的执行计划,下面的阶段值统计不到可能是bug

执行计划里面显示走到索引就是走到了,看你的sql耗时,应该是加锁耗时,不是sql执行耗时


而且这里还显示有锁冲突,是查询的数据有更改吗?不知道是不是for update 导致的,是不是可以去掉for update 操作一次看看是否有变化?不知道这个锁冲突是啥导致的

explain analyze试下呢,把执行计划发下,看是否和dashboard中一样

是锁冲突导致的,怀疑是锁表了,使用select for update是为了读到最新的数据,用的隔离级别是RR

执行计划和上面的是一致的

怀疑是锁表导致的,所以问题就是没走到索引上,如果走到索引上就不会锁表了。

看信息 好像只有锁表 没有解锁,所以是说这条SQL 和其他的SQL 发生了锁冲突?是谁锁谁?