使用复合索引优化MySQL查询

时间:2018-10-08 12:49:50

标签: mysql sql performance

我有一个表,当前有大约8000万行,创建方式如下:

SELECT
    records.id
FROM records
WHERE
    (records.status = 0 OR records.status = -10)
    AND records.created BETWEEN UNIX_TIMESTAMP() - 32 * 86400 AND UNIX_TIMESTAMP() - 8 * 86400
LIMIT 500

创建的列包含unix时间戳,状态可以是-10到10之间的整数。关于创建日期的记录是均匀分布的,其中大约一半处于状态0或-10。

我有一个cron,用于选择32天到8天之间的记录,对它们进行处理,然后针对某些状态将其删除。查询如下:

{{1}}

当记录在创建间隔的开始时查询很快,但是现在清理在间隔结束时到达了记录,运行大约需要10秒钟。对该查询进行解释说,它使用索引,但是它解析了大约4000万条记录。

我的问题是我是否可以做些什么来提高查询的性能,如果可以的话,如何精确地进行查询。

谢谢。

2 个答案:

答案 0 :(得分:1)

我认为union all是您最好的方法:

(SELECT r.id
 FROM records r
 WHERE r.status = 0 AND
       r.created BETWEEN UNIX_TIMESTAMP() - 32 * 86400 AND UNIX_TIMESTAMP() - 8 * 86400
 LIMIT 500
) UNION ALL
(SELECT r.id
 FROM records r
 WHERE r.status = -10 AND
       r.created BETWEEN UNIX_TIMESTAMP() - 32 * 86400 AND UNIX_TIMESTAMP() - 8 * 86400
 LIMIT 500
) 
LIMIT 500;

这可以使用records(status, created, id)上的索引。  注意:如果union可能有重复项,请使用records.id

您还使用了LIMIT,而没有ORDER BY。通常不建议这样做。

答案 1 :(得分:0)

您的索引顺序错误。您应该将IN列(status)首先放在(您将其列为OR),然后将'range'列(created)放在最后:

INDEX(status, created)

(不要给我有关“基数”的任何虚张声势;我们不在查看各个列。)

表中真的只有3列吗?您需要id吗?如果没有,请摆脱它并更改为

PRIMARY KEY(status, created)

其他techniques用于有效地浏览大型表。