使用三个单独的列来存储日期(年/月/日)的每个单独元素会在插入性能和磁盘空间方面给数据库增加不必要的开销。
您要做的只是有一个单独的DATETIME
列来存储日期和时间,并在(countryId, datetime_col)
.
即使您想根据特定的日期或月份查询所有行,MySQL 仍然能够利用 DATETIME 字段上的索引,前提是您以正确的方式编写查询并确保永远不会包装DATETIME 列执行条件检查时在函数内。
以下是编写查询的方法,以便它仍然能够利用索引:
-- Get the sum of totalNumber of all rows based on current day
-- where countryId = 1
SELECT SUM(totalNumber) AS totalsum
FROM tbl
WHERE countryId = 1 AND
datetime_col >= CAST(CURDATE() AS DATETIME) AND
datetime_col < CAST(CURDATE() + INTERVAL 1 DAY AS DATETIME)
通过在裸 DATETIME 列上进行比较,查询仍然是 sargable(即能够利用索引范围扫描)并且 MySQL 将能够使用索引来快速查找行。
另一方面,如果您尝试将 DATETIME 列包装在函数中以进行比较:
-- Get the sum of totalNumber of all rows based on current day
-- where countryId = 1
SELECT SUM(totalNumber) AS totalsum
FROM tbl
WHERE countryId = 1 AND
DATE(datetime_col) = CURDATE()
...这将是非常低效的,因为DATE()
包装列的函数有效地将查询呈现为不可分割,并且您设置的包含 DATETIME 列的任何类型的索引都不会被使用。
您还可以有效地查询当月所有行的总和:
-- Get the sum of totalNumber of all rows based on current month
-- where countryId = 1
SELECT SUM(totalNumber) AS monthsum
FROM tbl
WHERE countryId = 1 AND
datetime_col >= CAST(CONCAT(YEAR(NOW()), '-', MONTH(NOW()), '-01') AS DATETIME) AND
datetime_col < CAST(CONCAT(YEAR(NOW()), '-', MONTH(NOW()), '-01') AS DATETIME) + INTERVAL 1 MONTH
在本年度内:
-- Get the sum of totalNumber of all rows based on current year
-- where countryId = 1
SELECT SUM(totalNumber) AS yearsum
FROM tbl
WHERE countryId = 1 AND
datetime_col >= CAST(CONCAT(YEAR(NOW()), '-01-01') AS DATETIME) AND
datetime_col < CAST(CONCAT(YEAR(NOW()), '-01-01') AS DATETIME) + INTERVAL 1 YEAR