这些 MySQL 查询有效吗?

Col*_*bet 4 mysql performance

我花了很长时间来学习如何在 MySQL 中处理时间戳,我认为我实现了我的目标,但我想仔细检查两件事:

1)这些是否符合我的预期

2)这些查询/功能是否有更快的替代品

今天

SELECT COUNT(*) AS count FROM log WHERE DATE(datet) = DATE(NOW())
Run Code Online (Sandbox Code Playgroud)

本星期

SELECT COUNT(*) AS count FROM log WHERE YEARWEEK(NOW()) = YEARWEEK(datet)
Run Code Online (Sandbox Code Playgroud)

上个星期

SELECT COUNT(*) AS count FROM log WHERE YEARWEEK(datet) = YEARWEEK(DATE_SUB(NOW(), INTERVAL 1 WEEK))
Run Code Online (Sandbox Code Playgroud)

这个月

SELECT COUNT(*) AS count FROM log WHERE datet > DATE_SUB(NOW(), INTERVAL 1 MONTH)
Run Code Online (Sandbox Code Playgroud)

上个月

SELECT COUNT(*) AS count FROM log WHERE datet > DATE_SUB(NOW(), INTERVAL 2 MONTH) AND datet < DATE_SUB(NOW(), INTERVAL 1 MONTH)
Run Code Online (Sandbox Code Playgroud)

小智 10

由于 MySQL 必须评估表中每一行的函数输出,因此将datet列包装在函数中的查询效率不高(例如DATE(), YEARWEEK())。这将查询呈现为不可 sargable(即无法利用datet列上的索引)。

您似乎想要选择特定时间范围内所有记录的计数。为此,您必须使用>=,而不是=。此外,还有“之间的差异这个月”和“一个月内”。我假设你想要前者(即如果说今天是 8 月 3 日,你只想要 8 月内的记录,而不是从 7 月 3 日开始,以及一周的同样的事情,等等......)。

假设datet是一个DATETIME/TIMESTAMP列并且该列的值永远不会“在未来”,您可以像这样重写您的查询(每个查询都可以使用该datet列上的索引):

-- Today
SELECT COUNT(*) AS count 
FROM   log 
WHERE  datet >= CURDATE()
Run Code Online (Sandbox Code Playgroud)
-- This Week
SELECT COUNT(*) AS count 
FROM log 
WHERE datet >= CURDATE() - INTERVAL CASE WEEKDAY(CURDATE()) WHEN 6 THEN -1 ELSE WEEKDAY(CURDATE()) END + 1 DAY
Run Code Online (Sandbox Code Playgroud)
-- Last Week
SELECT COUNT(*) AS count 
FROM log 
WHERE datet >= (CURDATE() - INTERVAL CASE WEEKDAY(CURDATE()) WHEN 6 THEN -1 ELSE WEEKDAY(CURDATE()) END + 1 DAY) - INTERVAL 1 WEEK
      AND
      datet < CURDATE() - INTERVAL CASE WEEKDAY(CURDATE()) WHEN 6 THEN -1 ELSE WEEKDAY(CURDATE()) END + 1 DAY
Run Code Online (Sandbox Code Playgroud)
-- This Month
SELECT COUNT(*) AS count 
FROM   log 
WHERE  datet >= CURDATE() - INTERVAL DAYOFMONTH(CURDATE()) - 1 DAY
Run Code Online (Sandbox Code Playgroud)
 -- Last Month
SELECT COUNT(*) AS count 
FROM log 
WHERE datet >= (CURDATE() - INTERVAL DAYOFMONTH(CURDATE()) - 1 DAY) - INTERVAL 1 MONTH
      AND 
      datet < CURDATE() - INTERVAL DAYOFMONTH(CURDATE()) - 1 DAY
Run Code Online (Sandbox Code Playgroud)
-- This Year
SELECT COUNT(*) AS count 
FROM   log 
WHERE  datet >= MAKEDATE(YEAR(CURDATE()), 1)
Run Code Online (Sandbox Code Playgroud)