为什么不使用索引(在主键列上)?

时间:2018-02-20 13:28:22

标签: mysql indexing primary-key between

我有一个日期表,其中有一列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)
);

现在,我希望使用动态值从此表中选择行,例如LAST_DAY()DATE_SUB(DATE_FORMAT(SYSDATE(),'%Y-01-01'), INTERVAL X YEAR)等。

当我的一个查询失败并且在30秒内没有执行时,我知道有些东西是可疑的,看起来原因是没有使用主键列上的索引。这是我的结果(抱歉使用图像而不是复制查询,但我认为它的简洁性足够用于此目的,并且查询简短/简单):

enter image description here

首先,BETWEEN与使用>=<=的工作方式不同,这很奇怪。其次,看起来索引仅用于常量值。如果仔细观察,可以看到右侧(使用>=<=),它显示~9K行,这是表中行的一半(表中有关于~18k行,日期从2000-01-01到“2050-12-31”。

2 个答案:

答案 0 :(得分:1)

  

SYSDATE()返回执行的时间。这与NOW()的行为不同,后者返回一个表示语句开始执行的时间的常量时间。 (在存储的函数或触发器中,NOW()返回函数或触发语句开始执行的时间。)

- https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sysdate

也就是说,优化器不会将此视为“常量”。否则,优化器会急切地评估任何“常量表达式”,然后尝试利用知道值。

另请参阅sysdate_is_now选项。

结论:不要将SYSDATE()用于正常的日期时间使用;使用NOW()CURDATE()

答案 1 :(得分:0)

如果我使用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());

给出相同的结果,即:

enter image description here

我会接受我的答案作为解决方案,但我仍然在寻找解释。我认为可能必须做SYSDATE()而不是DATE,但NOW()也不是DATE ......

编辑:忘记添加,BETWEEN也正常工作。