未正确使用索引导致Out Of Memory Quota!

【 TiDB 使用环境】测试
【 TiDB 版本】7.0
【复现路径】sprinboot+mybatis
【遇到的问题:问题现象及影响】复杂的一条长sql,单独在navicat执行正常,通过程序(springboot+mybatis)执行时出现Out Of Memory Quota!,通过dashboard监控发现使用索引不同导致
程序执行sql使用索引:
[hd_iot_app:idx_mid,hd_iot_model:PRIMARY]
单独执行sql使用索引:
[hd_iot_app:idx_mid,hd_area_relation:idx_anc_des]

【资源配置】
【附件:截图/日志/监控】

可以在SQL里使用force index 来强制指定要使用的索引

查看下表的健康度和统计信息,可以执行analyze table 语句手动更新统计信息,然后再执行相同的SQL,应该能用到正确的索引

1 个赞

SQL和执行计划贴一下看看

use index 或者hint 试试

SELECT a.id,a.name,a.sn,a.code,a.kind,a.address,a.longitude,a.latitude, a.factory,a.category,a.model,a.created, a.aid,a.enable,a.sort,a.rid, a.last_data_time,a.status,a.meter_no,a.cust_no,a.comm_no,a.dev_type, b.name as areaName, b.code as areaCode, d.NAME as modelName, c.NAME AS appName, c.fetchFreq AS fetchFreq, c.offlineDelay AS offlineDelay, c.uploadFreq uploadFreq, c.offline_cycle offlineCycle, ‘device’ as type FROM hd_device a join hd_device_area b on b.id = a.category join hd_area_relation r on r.des = b.id left join hd_area_relation r1 on r.anc = r1.des join hd_iot_app c on c.id = a.aid JOIN hd_iot_model d ON c.mid = d.id left join hd_treenode_cate t on t.tid = a.id and t.target = ‘division’ left join hd_treenode n on n.id = t.nid left join hd_tag g on g.tid = a.id and g.target = ‘device’ WHERE 1=1 and ( c.mid = ‘db’ and r1.anc in ( ‘8Ur0Mq3YMHFU3wCis2Q6P#1’ ) ) group by a.id LIMIT 30

执行计划很长,没法发,大佬可以远程协助看下吗

单独在navicat中执行sql是没问题的,程序中的sql是动态的,最终生成的sql只有换行格式上存在差异

如果手动执行是没问题,那么就能确认到问题是由程序生成和执行SQL这一块内容引进的,重点排查下程序逻辑

程序里用prepare了么?,如果用了话可以试下在navicat里先prepare再指定参数时候,看下用的是哪个索引。

你的程序里面条件应该都是前台传过来的吧,而你通过客户端单独执行的条件都是你指定的,所以执行时间和执行计划不一样是合理的,你应该测试一下如果你前台传过来哪些条件能过滤出来最多的数据是不是量很大,而且LIMIT里后面是不是可以填非常大的数字,例如这样
SELECT
a.id,
a.name,
a.sn,
a.code,
a.kind,
a.address,
a.longitude,
a.latitude,
a.factory,
a.category,
a.model,
a.created,
a.aid,
a.enable,
a.sort,
a.rid,
a.last_data_time,
a.status,
a.meter_no,
a.cust_no,
a.comm_no,
a.dev_type,
b.name AS areaName,
b.code AS areaCode,
d.NAME AS modelName,
c.NAME AS appName,
c.fetchFreq AS fetchFreq,
c.offlineDelay AS offlineDelay,
c.uploadFreq uploadFreq,
c.offline_cycle offlineCycle,
‘device’ AS TYPE
FROM
hd_device a
JOIN hd_device_area b
ON b.id = a.category
JOIN hd_area_relation r
ON r.des = b.id
LEFT JOIN hd_area_relation r1
ON r.anc = r1.des
JOIN hd_iot_app c
ON c.id = a.aid
JOIN hd_iot_model d
ON c.mid = d.id
LEFT JOIN hd_treenode_cate t
ON t.tid = a.id
LEFT JOIN hd_treenode n
ON n.id = t.nid
LEFT JOIN hd_tag g
ON g.tid = a.id
WHERE 1 = 1
GROUP BY a.id LIMIT 10000000000
另外你如果在程序的连接串中配置了prepstmt的话,所有的sql走一样的执行计划,你要考虑下,当你选择条件最宽泛的时候,走这个执行计划还合不合适。

数据刚从mysql迁过来,之前运行在mysql的环境是没任何问题的

链接未开启prepstmt

这个sql中有几个表的数据量在300w左右,有一个表数据量在700w左右,前端传过来的limit有限制,目前发现问题limit值为30

那limit问题能排除掉,你说你数据是刚从mysql迁过来,之前运行在mysql的环境是没任何问题的,那应该只是单纯的sql执行计划走错了,不是前台开发的问题,而且你也没开启prepstmt,那你看下涉及表的统计信息是不是不是最新的,可以收集下统计信息,然后再看下执行计划

大佬,重新执行了analyze,已经可以执行成功了,感谢大佬,就是性能让似乎比不过mysql8.0,mysql8.0下同一个sql,执行计划相同,mysql8.0执行耗时0.4秒,tidb执行耗时19秒
刚接触这个,可以指一个性能优化方向么

确实可以了

可以在tidb的dashboard页面看下sql的执行详情,看看慢在哪一块,正常速度不应该差这么多

此话题已在最后回复的 60 天后被自动关闭。不再允许新回复。