执行计划不准

发现一句慢SQL

SELECT max( id ) FROM ua_ad_message WHERE task_id = ‘434362’
→ ;
±----------+
| max( id ) |
±----------+
| 390061695 |
±----------+
1 row in set (7.64 sec)

条件对应的数量
SELECT count() FROM ua_ad_message where task_id = ‘434362’;
±---------+
| count(
) |
±---------+
| 38392 |
±---------+

表索引
KEY idx_inner_batch_no_version (inner_batch_no,version),
KEY idx_task_id_tel (task_id,tel),
KEY idx_task_id_status (task_id,status)

执行计划

explain SELECT max( id ) FROM ua_ad_message WHERE task_id = ‘434362’;
±-------------------------------±--------±----------±--------------------±---------------------------------------------------------+
| id | estRows | task | access object | operator info |
±-------------------------------±--------±----------±--------------------±---------------------------------------------------------+
| StreamAgg_10 | 1.00 | root | | funcs:max(tidb_mycat_onesms.ua_ad_message.id)->Column#22 |
| └─Limit_14 | 1.00 | root | | offset:0, count:1 |
| └─TableReader_23 | 1.00 | root | | data:Limit_22 |
| └─Limit_22 | 1.00 | cop[tikv] | | offset:0, count:1 |
| └─Selection_21 | 1.00 | cop[tikv] | | eq(tidb_mycat_onesms.ua_ad_message.task_id, 434362) |
| └─TableFullScan_20 | 4333.97 | cop[tikv] | table:ua_ad_message | keep order:true, desc |
±-------------------------------±--------±----------±--------------------±---------------------------------------------------------+

执行计划来看是走全表扫描,全表估算4333

手动执行analyze table后执行计划不变

指定索引解决
ELECT /*+ USE_INDEX(ua_ad_message, idx_task_id_status) */ max(id) FROM ua_ad_message WHERE task_id = ‘434362’;
±----------+
| max(id) |
±----------+
| 390061695 |
±----------+

全表数量
SELECT count() FROM ua_ad_message;
±---------+
| count(
) |
±---------+
| 97841443 |
±---------+
1 row in set (6.30 sec)

analyze相关配置
mysql> show variables like ‘%analyze%’;
±---------------------------------------±------------+
| Variable_name | Value |
±---------------------------------------±------------+
| tidb_analyze_partition_concurrency | 1 |
| tidb_analyze_version | 2 |
| tidb_auto_analyze_end_time | 23:59 +0000 |
| tidb_auto_analyze_partition_batch_size | 1 |
| tidb_auto_analyze_ratio | 0.5 |
| tidb_auto_analyze_start_time | 00:00 +0000 |
| tidb_enable_analyze_snapshot | OFF |
| tidb_enable_auto_analyze | ON |
| tidb_enable_fast_analyze | OFF |
| tidb_max_auto_analyze_time | 43200 |
| tidb_mem_quota_analyze | -1 |
| tidb_persist_analyze_options | ON |
±---------------------------------------±------------+

请教是什么原因呢

重启下tidb server过一会儿再试试?

表结构 、explain anlyze 的执行计划 发下, 再试试SELECT /*+ AGG_TO_COP() */ 发下执行计划

是不是表健康度不高?估计是健康度过低导致执行了错误的执行计划。

个人感觉tidb统计信息预估值,本身就是存在误差,经过一系列优化,依旧存在问题,比如明确知道走什么索引,可以手动指定。
尽可能多的加上索引,有些组合索引可能有问题,根据自己脚本优化拆解。

explain 不准,要使用explain analyze

ID是主键吗? 感觉是优化器的问题,参考如下优化试试 SELECT id from ua_ad_message where task_id = ‘434362’ order by id desc limit 1; 最好是把表结构 explain analyze都打出来看看

1 个赞

指定索引感觉就是解决了问题,但是没有找到问题的根源,对研发来说研发可能要骂娘

表结构发出来,猜测你id是主键,因为你tablefullscan的时候keep order是true,TiDB可能认为,按照表有序的扫,很快就能把task_id=‘434362’的找到,TiDB是有类似的这样的毛病,总觉得排序代价大,其实你这个建立一个单task_id列的索引应该会更快。

:yum:那这个研发可以开掉了,情绪太不稳定了~

show stats_healthy 看看表的健康度

这个确实不是研发的问题,在我们公司不能sql一出问题就发版改程序把,既然没走最优的路线肯定dba解决问题啊

ua_ad_message 的task_id是主键吗