比较日期查询的性能
Comparing performance of query for year in date
以下三个查询在性能方面的比较如何?我正在尝试获取 year=2017:
的所有记录
使用EXTRACT
:
SELECT count(*), completed_by_id FROM table
WHERE EXTRACT(YEAR FROM completed_on)=2017
GROUP BY completed_by_id
# Took 11.8s
使用YEAR
:
SELECT count(*), completed_by_id FROM table
WHERE YEAR(completed_on)=2017
GROUP BY completed_by_id
# Took 5.15s
使用LIKE 'YEAR%
'
SELECT count(*), completed_by_id FROM table
WHERE completed_on LIKE '2017%'
GROUP BY completed_by_id
# Took 6.61s
注意:在我自己的测试中,我发现 YEAR()
是最快的,LIKE
是第二快的,EXTRACT()
成为最慢的。
table 中有大约 5M 行,completed_on
是 DATETIME
字段,已被索引。
您没有描述您的 table 或索引,因此所有关于查询性能的建议都是猜测。
如果您的 completed_on
列是 DATETIME
、DATE
或 TIMESTAMP
类型 和 它已编入索引,这查询的性能将大大优于您所显示的所有查询,并随着 table 的增长保持其性能。
SELECT count(*), completed_by_id
FROM table
WHERE completed_on >= '2017-01-01'
AND completed_on < '2017-01-01' + INTERVAL 1 YEAR
GROUP BY completed_by_id
为什么?它可以对索引进行范围扫描,而不是对每一行的值进行 nonsargable 函数调用。
请注意在日期范围的开头使用 >=
并在结尾使用 <
。我们想要包括从 2017 年元旦的第一刻开始到 但不包括 2018 年元旦的第一刻的所有行。BETWEEN
不能这样做,因为它在其范围末尾使用 <=
而不是 <
。
如果有索引,BETWEEN
和我展示的语法都使用范围扫描,并且执行大致相同。
为了加快此查询的最佳结果,请在 (completed_on, completed_by_id)
.
上使用复合索引
如果您将 completed_on 存储为 DATE 或 DATETIME,您可以使用:
SELECT count(*) as cnt, LEFT(completed_on, 4) AS year
FROM table
GROUP BY year
HAVING year=2017
以下三个查询在性能方面的比较如何?我正在尝试获取 year=2017:
的所有记录使用EXTRACT
:
SELECT count(*), completed_by_id FROM table
WHERE EXTRACT(YEAR FROM completed_on)=2017
GROUP BY completed_by_id
# Took 11.8s
使用YEAR
:
SELECT count(*), completed_by_id FROM table
WHERE YEAR(completed_on)=2017
GROUP BY completed_by_id
# Took 5.15s
使用LIKE 'YEAR%
'
SELECT count(*), completed_by_id FROM table
WHERE completed_on LIKE '2017%'
GROUP BY completed_by_id
# Took 6.61s
注意:在我自己的测试中,我发现 YEAR()
是最快的,LIKE
是第二快的,EXTRACT()
成为最慢的。
table 中有大约 5M 行,completed_on
是 DATETIME
字段,已被索引。
您没有描述您的 table 或索引,因此所有关于查询性能的建议都是猜测。
如果您的 completed_on
列是 DATETIME
、DATE
或 TIMESTAMP
类型 和 它已编入索引,这查询的性能将大大优于您所显示的所有查询,并随着 table 的增长保持其性能。
SELECT count(*), completed_by_id
FROM table
WHERE completed_on >= '2017-01-01'
AND completed_on < '2017-01-01' + INTERVAL 1 YEAR
GROUP BY completed_by_id
为什么?它可以对索引进行范围扫描,而不是对每一行的值进行 nonsargable 函数调用。
请注意在日期范围的开头使用 >=
并在结尾使用 <
。我们想要包括从 2017 年元旦的第一刻开始到 但不包括 2018 年元旦的第一刻的所有行。BETWEEN
不能这样做,因为它在其范围末尾使用 <=
而不是 <
。
如果有索引,BETWEEN
和我展示的语法都使用范围扫描,并且执行大致相同。
为了加快此查询的最佳结果,请在 (completed_on, completed_by_id)
.
如果您将 completed_on 存储为 DATE 或 DATETIME,您可以使用:
SELECT count(*) as cnt, LEFT(completed_on, 4) AS year
FROM table
GROUP BY year
HAVING year=2017