是否仍然正确日期/日期时间列上的索引未针对YEAR(col),MONTH(col)函数进行优化? Bill Karwin给出了一个非常确定的答案here,但由于这是十年前我想检查的。我原以为是因为日期栏被描述为
打包为YYYY×16×32 + MM×32 + DD
的三字节整数
它可以以这样一种方式编制索引:它可以像执行tight index scan时的多列索引一样进行优化。
这种优化仍然不存在吗?为什么不可能呢?
答案 0 :(得分:6)
正确。一旦WHERE子句中的列包含函数,MySQL优化器就不会使用索引。简单的推理是,一旦你在列my_date
上有一个索引,当你实际上在寻找不同的值时,数据库就没有意义在其中搜索,例如YEAR(my_date)的输出。
虽然好消息是在某些情况下有一个快速而简单的解决方案。
例如,可以使用不同的方法优化以下查询:
SELECT flight_company, count(*)
FROM flight_times
WHERE year(FlightDate) = 2017
group by flight_company
除了在WHERE子句中使用YEAR()函数之外,您可以使用范围条件替换函数调用,该范围条件将检查相同的内容:
SELECT flight_company, count(*)
FROM flight_times
WHERE FlightDate between '2017-01-01'
and '2018-01-01'
GROUP BY flight_company
虽然有些功能不能简单地替换为范围条件,例如在YEAR的情况下。例如,如何用条件替换dayofweek()?可能更难。 因此,另一种方法是使用MySQL 5.7 Virtual (generated) columns。如果你采用这种方法,你可以在CREATE TABLE语句中创建这个虚拟列,以实际匹配dayofweek()的结果:
Flight_dayofweek tinyint(4)
GENERATED ALWAYS AS (dayofweek(FlightDate
VIRTUAL
作为EverSQL的联合创始人,我将谦虚地建议您使用EverSQL SQL Query Optimizer自动优化此类查询。
答案 1 :(得分:4)
问题不在于日期的表示。问题是查询的优化。在日期列上使用YEAR()
和MONTH()
时,该列是参数的函数。
这意味着编译器将拥有大量有关该函数的信息,以便使用索引扫描或索引查找对其进行优化。如:
当然,这些都是可能的。实际上,挑战是将它们构建到函数定义和优化器中。没有人构建SQL优化器会想要为特定函数添加特殊情况(好吧,几乎没有人; SQL Server允许使用cast()
来利用索引)。
所以,你的问题的答案是比尔的答案仍然有效。