一个脑残索引问题

C 2019-4-19 2616

❌ 之前困扰半天的问题,刚才终于解决了

该方案被自己推翻,详见回复一楼。


就是一个数据表,里面有:

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,那么他就直接走索引了……


不过就是个先后顺序的问题,竟然折腾成这样,看来数据库不够智能啊,就不能预读一下排序规则,选出最优方案再排列吗?


最新回复 (1)
  • C 2019-4-19
    2
    该方案已被推翻,原因如下:

    例如有几个数据:
    a 11
    b 22
    c 33
    z 11

    如果我想查询 name 为 a/b/c/z,time 从小到大前三个数值
    那如果这样运行,查出来的结果是:a11/b22/c33,z因为按字母排列时已被忽略。

    所以还得按单条查询,无解。
    要么就多做一个索引,没有意义,浪费空间。