比较日期查询的性能

时间:2017-07-26 21:26:16

标签: mysql datetime database-performance query-performance

以下三个查询如何在性能方面进行比较?我试图获得年份= 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()是最慢的。

表格中有大约5M行,completed_on是已被编入索引的DATETIME字段。

2 个答案:

答案 0 :(得分:3)

您尚未描述您的表或索引,因此有关查询性能的所有建议都是猜测。

如果您的completed_on列是DATETIMEDATETIMESTAMP类型,则会将其编入索引,此查询将从根本上超越所有你展示的那些,并随着桌子的增长保持其性能。

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)上使用复合索引。

答案 1 :(得分:0)

如果您将completed_on存储为DATE或DATETIME,则可以使用:

SELECT count(*) as cnt, LEFT(completed_on, 4) AS year
FROM table 
GROUP BY year
HAVING year=2017