mod函数SQL优化问题

有个SQL,全表扫描,想要优化一下,目前不知从何下手
开发利用mod 把不同值写在不同的服务器上。相当于10个并发查询,表有4w多数据,想想有什么办法可以走索引减少数据量传输。这个sql看到每分钟数据读取十几G
image

SELECT id, task_id, channel_name,state,create_time
FROM
tmp_task t
WHERE
t.task_id mod 10 = 1
ORDER BY
state, create_time ASC
LIMIT 10;

有没有人懂 如何优化 mod函数的 :call_me_hand:

这个问题我们开发也经常干,我的做法是把取模改成范围,比如有100条数据1-100,范围方式就能很好利用索引了

是不是可以再加一列task_id_mod,然后task_id_mod,state,create_time三个列建一个索引。

我这个task-id值 不是固定的,是随机不清楚具体多少的值。

再加一列 这就要去提需求了,还要测试,改代码验证。比较麻烦,最好是看看在sql方面或者索引方面看看有没有办法

可以尝试创建表达式索引、或者反向索引,mod 10的话其实就是取最后一位like %1、%2…。

1.那你还可以用分页方式分
2.可以另外加一列,提前把模值写进去,用新的列建联合索引

刚和开发沟通了一下。整个SQL正常情况是查到数据之后如果状态是成功,则会把这个数据删掉。正常情况这个表应该不会超过1000条。但是他的中间件那边有问题。mod 10= 1-5的值没有传输来,这部分数据就没有正常的查询和删除。所以数据堆积越来越多 :joy:

这个mod是在中间件配置的,不是在代码里面写得。我用like测试了。也不走索引 :joy:
这个task_id是有索引的。

那你用分页方式是最好的,既控制了每个并发数量,又能用到索引,避免全表扫描

4%是4开头,%4是4结尾的和mod 10之后的结果是一样的,得先建个反序索引。

不是固定值,有范围么?如果范围小,直接上枚举或者枚举表

优化这块是真的不会了,听听大佬们怎么做

暂时范围是0-7000,这个值也不是固定的,也不清楚后面会不会随机到8000或者9000,现在就是这个where谓词条件式在中间件里面设定的,不是在代码,如果修改,改动比较大,暂时还在和开发商量,他去找找优化方案,如果不行打算按照上面说的新增加一列。

我刚开始想法是Mysql和Oracle都是最左侧原则,这个4%会走索引,在Tidb没有走。可能在这里不适合吧。

你说的分页是 先count(*)一下总行数,然后分10页,每页是总行数/10这样吗?这样的话,也是全表扫描,也是要把tikv4万数据传输到tidb去在排序。现在想要解决的就是不要tikv传输这么多数据到tidb

如果可以增加一列,将task_id的值先mod进去,建这个字段的索引的话,可以优化一下。要不就是SQL中增加条件,用另外的字段做为主索引查询

恩,暂时让开发想想其他办法,如果想不到的话,我们准备增加一列。sql没有任何条件可以添加,就是要全表数据,只不过他说中间件出了问题,这个表数据量变多了。 :joy:

https://docs.pingcap.com/zh/tidb/stable/dev-guide-paginate-results#分页查询