为什么 whereDate() 可能会影响性能以及如何修复
你是否曾经运行过一个 Laravel 作业,突然开始超时,你盯着你的 SQL 想知道为什么?
下例是我调试一个长时运行的利息计算作业,直到我发现了罪魁祸首:
->whereDate('created_at', '>=', $from)
->whereDate('created_at', '<=', $to)
WHERE DATE(`created_at`) >= '2024-06-10'
AND DATE(`created_at`) <= '2024-06-17'看起来很无辜,对吧?但是 whereDate() 将 created_at 字段包装在 DATE() 中,这会禁用你的索引。
这意味着 MySQL 必须扫描每一行以进行匹配,即使你的 created_at 字段已被索引。
即使你一直在使用 Eloquent,当你使用 ->whereDate() 时,它仍然会扫描整个表,因为在底层它生成的是这样的原始 SQL:
->whereDate('created_at', '>=', $from)生成:
WHERE DATE(created_at) >= '2024-06-10'这就禁用了索引。
如何修复?使用完整的时间戳:
->where('created_at', '>=', $from->startOfDay())
->where('created_at', '<=', $to->endOfDay())这样原始 SQL 为:
created_at BETWEEN '2024-06-10 00:00:00' AND '2024-06-10 23:59:59'而且确实使用了 created_at 的索引。
曾经超时的查询现在在几毫秒内运行,因为索引的使用。