使用复合索引优化MySQL查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用复合索引优化MySQL查询相关的知识,希望对你有一定的参考价值。

我有一个目前有大约8000万行的表,创建如下:

create table records
(
  id      int auto_increment primary key,
  created int             not null,
  status  int default '0' not null
)
  collate = utf8_unicode_ci;

create index created_and_status_idx
  on records (created, status);

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

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

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

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

我的问题是,如果有什么我可以做的来提高查询的性能,如果有的话,究竟是怎样的。

谢谢。

答案

我认为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

你也使用没有LIMITORDER BY。这通常是气馁的。

另一答案

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

INDEX(status, created)

(不要给我任何关于“基数”的guff;我们不会看单个列。)

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

PRIMARY KEY(status, created)

其他techniques有效地走过大桌子。

以上是关于使用复合索引优化MySQL查询的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点#MySQL索引优化系列:索引全用及最左法则

有关于mysql复合索引

mysql:联合索引及优化

mysql 优化策略(如何利用好索引)

MySQL 18条优化技巧

mysql-优化一