How to Optimize This Slow Query

Note:
This topic has been translated from a Chinese forum by GPT and might contain errors.

Original topic: 如何优化这个慢查询

| username: 大飞飞呀

[TiDB Usage Environment] Production Environment
[TiDB Version]
[Reproduction Path] What operations were performed to reproduce the issue
SELECT I_ID from table_name FORCE index (IDX_SYNC_STATUS)
WHERE I_SYNC_STATUS = 0 LIMIT 1000;
[Encountered Issue: Problem Phenomenon and Impact]
There are not many records with I_SYNC_STATUS = 0 in the table, a total of more than 1000.
The table has 2.4 billion records, but even with the forced index, why is the query still slow?

explain analyze sql


CREATE TABLE st_summary_bill_sync_confirm (
I_ID bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘Auto-increment ID’,
I_SUMMARY_ID bigint(20) NOT NULL DEFAULT ‘0’ COMMENT ‘’,
I_SUMMARY_TYPE int(11) NOT NULL DEFAULT ‘0’ COMMENT ‘’,
I_SYNC_STATUS tinyint(4) NOT NULL DEFAULT ‘0’ COMMENT ‘Sync status: 0 for ready to sync, 1 for syncing, 2 for sync successful, 3 for sync failed, 4 for unprocessed type’,
I_SYNC_STATUS_DETAIL int(11) NOT NULL DEFAULT ‘0’ COMMENT ‘Detailed status information’,
I_RETRY_COUNT int(11) NOT NULL DEFAULT ‘0’ COMMENT ‘Retry count’,
CH_COMMENT varchar(200) NOT NULL DEFAULT ‘’ COMMENT ‘Sync-related comments’,
D_CREATED_AT datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ‘Creation time’,
D_UPDATED_AT datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ‘’,
PRIMARY KEY (I_ID) /*T![clustered_index] CLUSTERED */,
UNIQUE KEY UNIQ_SUMMARY_ID (I_SUMMARY_ID),
KEY IDX_SYNC_STATUS (I_SYNC_STATUS)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=2588993678 COMMENT=‘’
[Resource Configuration]
[Attachments: Screenshots/Logs/Monitoring]

| username: xfworld | Original post link

How slow is it?

| username: 大飞飞呀 | Original post link

100 seconds

| username: xfworld | Original post link

Could you provide more details on the information in the second image?

What kind of index is IDX_SYNC_STATUS? I suspect it is a hotspot index, so it’s normal for it to be slow. :see_no_evil:

| username: 大飞飞呀 | Original post link

Not a hotspot index, detailed data

Limit_9, 1000.00, 96, root, , time:1.82s, loops:2, offset:0, count:1000, N/A, N/A
└─IndexLookUp_14, 1000.00, 96, root, , time:1.82s, loops:2, index_task: {total_time: 1.44s, fetch_handle: 1.44s, build: 1.68µs, wait: 7.03µs}, table_task: {total_time: 11.5s, num: 1, concurrency: 8}, , 11.1 KB, N/A
├─Limit_13(Build), 1000.00, 96, cop[tikv], , time:1.44s, loops:3, cop_task: {num: 1478, max: 252ms, min: 189.3µs, avg: 954µs, p95: 439.3µs, max_proc_keys: 96, p95_proc_keys: 0, tot_proc: 919ms, tot_wait: 50ms, rpc_num: 1478, rpc_time: 1.4s, copr_cache_hit_ratio: 0.99}, tikv_task:{proc max:354ms, min:39ms, p80:138ms, p95:189ms, iters:1480, tasks:1478}, scan_detail: {total_process_keys: 96, total_keys: 3811337, rocksdb: {delete_skipped_count: 1823, key_skipped_count: 4558158, block: {cache_hit_count: 2483, read_count: 2, read_byte: 16.6 KB}}}, offset:0, count:1000, N/A, N/A
│ └─IndexRangeScan_11, 1000.00, 96, cop[tikv], table:st_summary_bill_sync_confirm, index:IDX_SYNC_STATUS(I_SYNC_STATUS), tikv_task:{proc max:354ms, min:39ms, p80:138ms, p95:189ms, iters:1480, tasks:1478}, 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}}}, range:[0,0], keep order:false, N/A, N/A
└─TableRowIDScan_12(Probe), 1000.00, 96, cop[tikv], table:st_summary_bill_sync_confirm, time:794.2µs, loops:2, cop_task: {num: 1, max: 726.5µs, proc_keys: 96, rpc_num: 1, rpc_time: 706.3µs, copr_cache_hit_ratio: 0.00}, tikv_task:{time:0s, loops:3}, scan_detail: {total_process_keys: 96, total_keys: 289, rocksdb: {delete_skipped_count: 96, key_skipped_count: 864, block: {cache_hit_count: 10, read_count: 0, read_byte: 0 Bytes}}}, keep order:false, stats:pseudo, N/A, N/A

| username: forever | Original post link

What is the table structure? Is it a clustered table or a non-clustered table? Is I_ID the primary key?

| username: tidb狂热爱好者 | Original post link

This is normal. The distinction is too low.

| username: xfworld | Original post link

You can use EXPLAIN ANALYZE SQL to collect the actual execution details.

According to the description, the statistics of the related tables are not very accurate. You should first execute ANALYZE TABLE to update the statistics.

Then, collect the execution details again using EXPLAIN ANALYZE SQL and compare the results.

| username: 大飞飞呀 | Original post link

The default value of tidb_dml_batch_size is 2000. You can adjust it according to your needs.

| username: Kongdom | Original post link

I see stats:pseudo, it is recommended to run analyze first to collect some statistics.

| username: 大飞飞呀 | Original post link

This table is updated quite frequently, so the analyze table might become invalid after a while. Also, since I have already used the index, it should definitely use the index, right?

| username: Kongdom | Original post link

How is the speed without the limit?

| username: 大飞飞呀 | Original post link

There are a total of 1000 entries with status=0.

| username: 大飞飞呀 | Original post link

Sometimes the same SQL query is very fast, detailed information:
Projection_4, 5510288.92, 0, root, , time:506.7ms, loops:1, Concurrency:8, stat.st_summary_bill_sync_confirm.i_summary_id, 8.72 KB, N/A
└─IndexLookUp_7, 5510288.92, 0, root, , time:506.6ms, loops:1, table_task: {total_time: 4.02s, num: 0, concurrency: 8}, , 1.14 KB, N/A
├─IndexRangeScan_5(Build), 5510288.92, 0, cop[tikv], table:st_summary_bill_sync_confirm, index:IDX_SYNC_STATUS(I_SYNC_STATUS), time:502.9ms, loops:1, cop_task: {num: 1478, max: 466.1ms, min: 172.3µs, avg: 648.4µs, p95: 400.6µs, tot_proc: 513ms, tot_wait: 56ms, rpc_num: 1478, rpc_time: 947.1ms, copr_cache_hit_ratio: 1.00}, tikv_task:{proc max:465ms, min:44ms, p80:139ms, p95:189ms, iters:1478, tasks:1478}, scan_detail: {total_process_keys: 0, total_keys: 1567009, rocksdb: {delete_skipped_count: 251214, key_skipped_count: 2886335, block: {cache_hit_count: 1640, read_count: 0, read_byte: 0 Bytes}}}, range:[0,0], keep order:false, N/A, N/A
└─TableRowIDScan_6(Probe), 5510288.92, 0, cop[tikv], table:st_summary_bill_sync_confirm, , keep order:false, N/A, N/A

| username: tidb狂热爱好者 | Original post link

You have so many historical keys, it should be a GC issue. Change the GC time to 10 minutes.

| username: 大飞飞呀 | Original post link

How to modify it? Are there specific commands? Please advise.

| username: Kongdom | Original post link

If it’s sometimes fast and sometimes slow, it could be a hotspot issue.

| username: Kongdom | Original post link

GC is a global system variable, assigned through the set method

| username: 大飞飞呀 | Original post link

A normal select query will check historical version data? That’s not scientific.

| username: 大飞飞呀 | Original post link

Fast: scan_detail: {total_process_keys: 78, total_keys: 1234511
Slow: scan_detail: {total_process_keys: 1111, total_keys: 136036179
I found a pattern: every time it’s slow, the total_keys is particularly large.