为什么不使用索引(在主键列上)?
Why Index (on primary key column) is not used?
我有一个日期 table,其中有一列 date
(PK)。 CREATE
脚本在这里:
CREATE TABLE date_table (
date DATE
,year INT(4)
,month INT(2)
,day INT(2)
,month_pad VARCHAR(2)
,day_pad VARCHAR(2)
,month_name VARCHAR(10)
,year_month_index INT(6)
,year_month_hypname VARCHAR(7)
,year_month_name VARCHAR(15)
,week_day_index INT(1)
,day_name VARCHAR(9)
,week INT(2)
,week_interval VARCHAR(13)
,weekend_fl INT(1)
,quarter_num INT(1)
,quarter_num_pad VARCHAR(2)
,quarter_name VARCHAR(2)
,year_quarter_index INT(6)
,year_quarter_name VARCHAR(7)
,PRIMARY KEY (date)
);
现在我想要来自此 table 的 select 行具有动态值,使用 LAST_DAY()
或 DATE_SUB(DATE_FORMAT(SYSDATE(),'%Y-01-01'), INTERVAL X YEAR)
等
当我的一个查询失败并且没有在 30 秒内执行时,我知道有问题,看起来原因是主键列上的索引没有被使用。这是我的结果(很抱歉使用图像而不是复制查询,但我认为它足够简洁用于此目的,并且查询足够short/simple):
首先,BETWEEN
与 >=
和 <=
的工作方式不同,这很奇怪。其次,索引看起来只用于常量值。如果仔细观察,您会发现在右侧(使用 >=
和 <=
的地方)显示了 ~9K 行,这是 table 中行数的一半( table 有大约 18k 行,日期从 2000-01-01
到 `2050-12-31).
看起来如果我使用 CURRENT_DATE()
(或 NOW()
)而不是 SYSDATE()
,它就可以工作。这两个查询:
SELECT *
FROM date_table t
WHERE 1 = 1
AND t.ddate >= LAST_DAY(CURRENT_DATE()) AND t.ddate <= LAST_DAY(CURRENT_DATE());
SELECT *
FROM date_table t
WHERE 1 = 1
AND t.ddate >= LAST_DAY(NOW()) AND t.ddate <= LAST_DAY(NOW());
给出同样的结果,就是这样:
我会接受我的回答作为解决方案,但我仍在寻找解释。我认为这可能与 SYSDATE()
不是 DATE
相关,但 NOW()
也不是 DATE
...
编辑: 忘记补充了,BETWEEN
也如我所见。
SYSDATE() returns the time at which it executes. This differs from the behavior for NOW(), which returns a constant time that indicates the time at which the statement began to execute. (Within a stored function or trigger, NOW() returns the time at which the function or triggering statement began to execute.)
-- https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sysdate
也就是说,优化器不会将此视为 "constant"。否则,优化器急切地评估任何 "constant expressions",然后尝试利用已知的价值。
另请参阅 sysdate_is_now
选项。
底线:不要将 SYSDATE()
用于正常的日期时间用法;使用 NOW()
或 CURDATE()
.
我有一个日期 table,其中有一列 date
(PK)。 CREATE
脚本在这里:
CREATE TABLE date_table (
date DATE
,year INT(4)
,month INT(2)
,day INT(2)
,month_pad VARCHAR(2)
,day_pad VARCHAR(2)
,month_name VARCHAR(10)
,year_month_index INT(6)
,year_month_hypname VARCHAR(7)
,year_month_name VARCHAR(15)
,week_day_index INT(1)
,day_name VARCHAR(9)
,week INT(2)
,week_interval VARCHAR(13)
,weekend_fl INT(1)
,quarter_num INT(1)
,quarter_num_pad VARCHAR(2)
,quarter_name VARCHAR(2)
,year_quarter_index INT(6)
,year_quarter_name VARCHAR(7)
,PRIMARY KEY (date)
);
现在我想要来自此 table 的 select 行具有动态值,使用 LAST_DAY()
或 DATE_SUB(DATE_FORMAT(SYSDATE(),'%Y-01-01'), INTERVAL X YEAR)
等
当我的一个查询失败并且没有在 30 秒内执行时,我知道有问题,看起来原因是主键列上的索引没有被使用。这是我的结果(很抱歉使用图像而不是复制查询,但我认为它足够简洁用于此目的,并且查询足够short/simple):
首先,BETWEEN
与 >=
和 <=
的工作方式不同,这很奇怪。其次,索引看起来只用于常量值。如果仔细观察,您会发现在右侧(使用 >=
和 <=
的地方)显示了 ~9K 行,这是 table 中行数的一半( table 有大约 18k 行,日期从 2000-01-01
到 `2050-12-31).
看起来如果我使用 CURRENT_DATE()
(或 NOW()
)而不是 SYSDATE()
,它就可以工作。这两个查询:
SELECT *
FROM date_table t
WHERE 1 = 1
AND t.ddate >= LAST_DAY(CURRENT_DATE()) AND t.ddate <= LAST_DAY(CURRENT_DATE());
SELECT *
FROM date_table t
WHERE 1 = 1
AND t.ddate >= LAST_DAY(NOW()) AND t.ddate <= LAST_DAY(NOW());
给出同样的结果,就是这样:
我会接受我的回答作为解决方案,但我仍在寻找解释。我认为这可能与 SYSDATE()
不是 DATE
相关,但 NOW()
也不是 DATE
...
编辑: 忘记补充了,BETWEEN
也如我所见。
SYSDATE() returns the time at which it executes. This differs from the behavior for NOW(), which returns a constant time that indicates the time at which the statement began to execute. (Within a stored function or trigger, NOW() returns the time at which the function or triggering statement began to execute.)
-- https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sysdate
也就是说,优化器不会将此视为 "constant"。否则,优化器急切地评估任何 "constant expressions",然后尝试利用已知的价值。
另请参阅 sysdate_is_now
选项。
底线:不要将 SYSDATE()
用于正常的日期时间用法;使用 NOW()
或 CURDATE()
.