2

我有一个 sql 查询

 SELECT level, data, string, soln, uid 
 FROM user_data 
 WHERE level = 10 AND (timetaken >= 151 AND timetaken <= 217) AND uid != 1
 LIMIT 8852, 1;

它从包含 150 万个条目的表中获取。

我已使用索引

alter table user_data add index a_idx (level, timetaken, uid); 

所以我面临的问题是在某些情况下查询需要超过 30 秒,在某些情况下不到 0.01 秒。

这里的索引有什么问题吗?

编辑:添加了解释查询详细信息

+----+-------------+------------------+-------+---------------+------------+---------+------+-------+--------------------------+
| id | select_type | table            | type  | possible_keys | key        | key_len | ref  | rows  | Extra                    |
+----+-------------+------------------+-------+---------------+------------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | user_data | range | a_idx    | a_idx | 30      | NULL | 24091 | Using where; Using index |
+----+-------------+------------------+-------+---------------+------------+---------+------+-------+--------------------------+

表中的数据字段是一个文本字段。在大多数情况下,它的长度大于 255 个字符。这会导致问题吗?

4

2 回答 2

0

首先,您应该尝试使用 EXPLAIN 获取此查询的执行计划:

 EXPLAIN SELECT level, data, string, soln, uid 
 FROM user_data 
 WHERE level = 10 AND (timetaken >= 151 AND timetaken <= 217) AND uid != 1
 LIMIT 8852, 1;

这是关于这个主题的一张很棒的幻灯片: http ://www.slideshare.net/phpcodemonkey/mysql-explain-explained

尝试添加不同的索引:

  • 一个关于 uid 和 level
  • 一个单独的时间
于 2013-01-10T11:10:15.203 回答
0

问题在于高偏移。为了选择第 8853 个结果,MySQL 必须在此之前扫描所有 8852 行。

顺便说一句,使用没有 order by 的 limit 可能会导致意想不到的结果。

为了加快具有高偏移量的查询,您应该使用 since..until 分页策略

于 2013-01-10T13:31:58.007 回答