❌ 之前困扰半天的问题,刚才终于解决了!
该方案被自己推翻,详见回复一楼。
就是一个数据表,里面有:
name | varchar
time | int
两个字段,索引 name-time,10万+数据。
我用一个语句:
SELECT * FROM `data` WHERE `name` IN ('a','b','c') AND `time`<1555632005 ORDER BY `time` DESC LIMIT 10
这样查询,会走 filesort 重排,造成查询效率异常低下。
而使用:
SELECT * FROM `data` WHERE `name`="a" AND `time`<1555632005 ORDER BY `time` DESC LIMIT 10
这样指定 name 后查询就直接走索引,基本 0.001s 内完成。
于是我非常蛋疼地写了个函数,查询三次 name 等于 a, b, c 的结果,然后 UNION ALL,再重排。
这样虽然造成了额外的查询操作,但是走索引可以减缓mysql读取压力。
刚刚发现原来有个更简单的办法,就是直接把第一条语句改为:
SELECT * FROM `data` WHERE `name` IN ('a','b','c') AND `time`<1555632005 ORDER BY `name` DESC AND `time` DESC LIMIT 10
就是在 ORDER BY 里加入 `name` 这个项,意思是排序时先按 name 顺序,再按 time 顺序。
这样我先把数据读取出来,再按 time 重排就可以了,相比之前省了很多工夫。
MySQL简直智障!之前的问题不过是我指定了按 time 排序,他居然就先把整个数据库按 time 排序一遍,然后再从里读取 a, b, c 各项开头的值。而如果我直接指定 a, b, c 开头,那它才可以直接按索引中 time 排序。如果我指定排序同索引 name-time,那么他就直接走索引了……
不过就是个先后顺序的问题,竟然折腾成这样,看来数据库不够智能啊,就不能预读一下排序规则,选出最优方案再排列吗?