我正在使用MySQL 5.7。
有一个名为transactions
的表,其中包含超过 300 万条记录。表架构如下所示:
id
- INT(自动增量(deleted_at
(日期时间,允许空(record_status
(TINYINT,默认值为 1(- 与此表相关的其他列...
record_status
是deleted_at
的整数版本。删除记录时,该值设置为 0。还会为此列创建一个索引。
基于空的 DATETIME 查询需要740 ms
才能执行:
select transactions.id from transactions where transactions.deleted_at is null
基于 TINYINT 的查询需要15.1 s
才能执行:
select transactions.id from transactions where transactions.record_status = 1
对 TINYINT 列(带索引(的检查不是应该更快吗?为什么会这样?
[编辑]
添加了有关表性能的信息
为了进一步进行实验,从表中删除了所有不必要的列。只有以下情况仍然存在。
id
- INT(自动增量(deleted_at
(日期时间,允许空(record_status
(TINYINT,默认值为 1(transaction_time
(日期时间(
查询 1:需要 2.3 毫秒
select transactions.id from transactions
where transactions.record_status = 1 limit 1000000;
查询 2:需要 2.1 毫秒
select transactions.id from transactions
where transactions.deleted_at is null limit 1000000;
查询 3:需要 20 秒
select transactions.id from transactions
where transactions.record_status = 1
and transaction_time > '2020-04-01' limit 1000;
查询 4:需要 500 毫秒
select transactions.id from transactions
where transactions.deleted_at is null
and transaction_time > '2020-04-01' limit 1000;
查询 5:394ms
select transactions.id from transactions
where transaction_time > '2020-04-01' limit 1000000;
我无法弄清楚为什么查询 3 需要这么长时间。
此问题已通过添加复合索引得到解决。
以下两种方法现在都会导致快速性能。
transaction_time
和deleted_at
上的复合键。transaction_time
和record_status
上的复合键。
感谢@Gordon利诺夫和@jarlh。他们的建议导致了这一发现。
select transactions.id from transactions
where transactions.record_status = 1
and transaction_time > '2020-04-01' limit 1000;
如果没有这样的复合索引,则无法优化 - 按以下顺序:
INDEX(record_status, transaction_time)
(不可以,两个单独的单列索引也不起作用。