MySQL sysdate()函数 不走索引的问题

下面说明了SYSDATE()函数的语法:

SYSDATE(fsp);

SQL

如果函数用于字符串上下文或YYYYMMDDHHMMSS格式,则SYSDATE()函数将返回当前日期时间,格式为“YYYY-MM-DD HH:MM:SS”的值,以防在函数用于数字上下文。

SYSDATE()函数接受一个可选参数fsp,它确定结果是否应该包含从06的小数秒精度。

请参见以下示例 -

mysql> SELECT SYSDATE();
+---------------------+
| SYSDATE()           |
+---------------------+
| 2017-08-10 20:43:16 |
+---------------------+
1 row in set

SQL

如果您传递fsp参数,则结果将包括小数秒精度,如以下示例所示:

mysql> SELECT SYSDATE(3);
+-------------------------+
| SYSDATE(3)              |
+-------------------------+
| 2017-08-10 20:43:46.985 |
+-------------------------+
1 row in set

SQL

SYSDATE 与 NOW 比较

请考虑以下示例 -

mysql> SELECT SYSDATE(), NOW();
+---------------------+---------------------+
| SYSDATE()           | NOW()               |
+---------------------+---------------------+
| 2017-08-10 20:44:38 | 2017-08-10 20:44:38 |
+---------------------+---------------------+
1 row in set

SQL

似乎SYSDATE()NOW()函数都返回一个相同的值,它是执行语句时当前日期和时间。

然而,SYSDATE()函数实际上返回执行时的时间,而NOW()函数返回一个常量时间,该语句开始执行。

请参阅以下查询:

mysql> SELECT NOW(), SLEEP(5), NOW();
+---------------------+----------+---------------------+
| NOW()               | SLEEP(5) | NOW()               |
+---------------------+----------+---------------------+
| 2017-08-10 20:46:51 |        0 | 2017-08-10 20:46:51 |
+---------------------+----------+---------------------+
1 row in set

SQL

在这个例子中,我们使用SLEEP()函数暂停查询5秒。 在同一个语句中,NOW()函数总是返回一个常量,它是语句开始的时间。

我们将NOW()函数更改为SYSDATE()函数:

mysql>  SELECT SYSDATE(), SLEEP(5), SYSDATE();
+---------------------+----------+---------------------+
| SYSDATE()           | SLEEP(5) | SYSDATE()           |
+---------------------+----------+---------------------+
| 2017-08-10 20:48:14 |        0 | 2017-08-10 20:48:19 |
+---------------------+----------+---------------------+
1 row in set

SQL

在同一个语句中,SYSDATE()函数返回反映SYSDATE()函数执行时间的不同时间值。

因为SYSDATE()函数是非确定性的,索引不能用于评估求值引用它的表达式。

为了演示这个,我们创建一个名为tests的表,并将一些数据插入到这个表中。

CREATE TABLE tests (
    id INT AUTO_INCREMENT PRIMARY KEY,
    t DATETIME UNIQUE
);


INSERT INTO tests(t) 
WITH RECURSIVE times(t) AS
( 
    SELECT now() - interval 1 YEAR t
        UNION ALL 
    SELECT t + interval 1 hour
    FROM times
    WHERE t < now() 
)
SELECT t
FROM times;

SQL

请注意,我们使用递归CTE来生成时间序列。 CTE从MySQL 8.0开始才有的功能。

因为t列有唯一索引,所以下列查询应该执行得很快:

SELECT 
    id, 
    t
FROM
    tests
WHERE
    t >= SYSDATE() - INTERVAL 1 DAY;

SQL

但是,需要15ms才能完成。让我们使用EXPLAIN语句来看看细节。

EXPLAIN SELECT 
    id, t
FROM
    tests
WHERE
    t >= SYSDATE() - INTERVAL 1 DAY;

SQL

执行上面分析语句,得到类似以下结果 -

原来,MySQL必须扫描表中的所有行才能获取数据。该索引无法使用。

如果在查询中将SYSDATE()更改为NOW()函数:

SELECT 
    id, 
    t
FROM
    tests
WHERE
    t >= NOW() - INTERVAL 1 DAY;

SQL

使用NOW()函数,索引已被用于查询数据,如下面的EXPLAIN结果所示:

EXPLAIN SELECT 
    id, 
    t
FROM
    tests
WHERE
    t >= NOW() - INTERVAL 1 DAY;

SQL

请注意,MySQL为您提供了--sysdate-is-now选项,可以使SYSDATE()函数的行为与NOW()函数相同。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值