简单的 MySQL 查询随机需要永远

mik*_*e14 5 mysql performance optimization

我的服务器上有一个简单的 PHP 发送电子邮件脚本的问题,该脚本通过 cronjob 每分钟运行一次。该脚本包含一个在大多数情况下运行速度非常快的 MySQL 查询,但随机将“永远”运行。

感觉就像一个类似的问题:https : //stackoverflow.com/questions/976739/mysql-query-randomly-takes-forever

在运行 MySQL 查询时,在看似随机的时间里,我的服务器上的负载从平均 0.5 激增到 8,我的整个服务器慢慢地接近停止。查询最终会完成,但有时会运行超过 10 分钟——在“正常”情况下,查询会在 0.2 秒内完成。

这是查询:

SELECT * FROM email_messages 
WHERE time_created <= "2013-04-22 10:40:00" AND is_sent = 0 AND is_cancelled = 0 
LIMIT 6
Run Code Online (Sandbox Code Playgroud)

time_created 是(应该)索引 - 其目的是在发送前创建一个 10 分钟的延迟,以便在必要时取消电子邮件。

我已将其与此查询隔离,因为当此 cronjob 关闭时,我的服务器运行良好,而没有平均负载峰值。

我的服务器是具有 2GB RAM 的 VPS。数据库并不大(总共 750mb),但选择的 email_messages 表是迄今为止最大的,大约 400mb。

经过研究,我认为是MySQL查询缓存问题,因为打开了查询缓存。但是关闭查询缓存并没有解决问题。

我通过设置关闭了 query_cache query_cache_size = 0

关于这里可能发生什么的任何想法?

[结论]

我做了一个实验,通过使用我的主键在查询中包含一个条件,以便只搜索最后 1000 个表条目。

... AND id > 131000 ...
Run Code Online (Sandbox Code Playgroud)

在这种情况下运行 cronjob 解决了这个问题,在 mysql 控制台中进一步调查EXPLAIN发现索引time_created 没有按照我的预期创建。

我现在需要阅读如何使用HeidiSQL正确创建索引,因为 HeidiSQL 告诉我有一个索引键,time_createdEXPLAIN另有说明。这可能是年轻球员的陷阱!

Joc*_*lyn 3

为了加快查询的执行速度,您需要创建复合索引:

ALTER TABLE email_messages
ADD INDEX idx1(is_sent, is_cancelled, time_created);
Run Code Online (Sandbox Code Playgroud)

详细信息:多列索引

  • 如果您创建 `time_created, is_sent, is_cancelled` 索引并查询 `time_created &lt;= "2013-04-22 10:40:00" AND is_sent = 0 AND is_cancelled = 0 ` - 那么 `is_sent, is_cancelled` 索引部分将不会被曾经使用过,因为“time_created”是范围比较。列的顺序应该相反。 (2认同)
  • @mike14:当你尝试它时 - 使用“is_sent、is_cancelled、time_created”顺序,而不是这个答案中建议的顺序。PS:只要是 VPS - 难怪有时 I/O 不好,所以我不指望这个复合索引会修复它,但毫无疑问它会让执行计划更好 (2认同)