使用复合索引优化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
。
你也使用没有LIMIT
的ORDER BY
。这通常是气馁的。
另一答案
您的索引顺序错误。你应该首先把IN
列(status
)(你把它称为OR
),并将'range'列(created
)放在最后:
INDEX(status, created)
(不要给我任何关于“基数”的guff;我们不会看单个列。)
表中真的只有3列吗?你需要id
吗?如果没有,摆脱它并改为
PRIMARY KEY(status, created)
其他techniques有效地走过大桌子。
以上是关于使用复合索引优化MySQL查询的主要内容,如果未能解决你的问题,请参考以下文章