1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-32148 Inefficient WHERE timestamp_column=datetime_const_expr

Changing the way how a the following conditions are evaluated:

    WHERE timestamp_column=datetime_const_expr

(for all comparison operators: =, <=>, <, >, <=, >=, <> and for NULLIF)

Before the change it was always performed as DATETIME.
That was not efficient, as involved per-row TIMESTAMP->DATETIME conversion
for timestamp_column. For example, in case of the SYSTEM time zone
it involved a localtime_r() call, which is known to be slow.

After the change it's performed as TIMESTAMP in many cases.
This allows to avoid per-row conversion, as it works the other way around:
datetime_const_expr is converted to TIMESTAMP once before the execution stage.

Note, datetime_const_expr must be inside monotone continuous periods of
the current time zone, i.e. not near these anomalies:
- DST changes (spring forward, fall back)
- leap seconds
This commit is contained in:
Alexander Barkov
2023-09-12 11:27:54 +04:00
parent af4f9daeb8
commit 351a8eecf0
23 changed files with 1543 additions and 24 deletions

View File

@ -630,3 +630,155 @@ SELECT a, UNIX_TIMESTAMP(a) FROM t1 ORDER BY a;
SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a <= ALL (SELECT * FROM t1);
SELECT a, UNIX_TIMESTAMP(a) FROM t1 WHERE a >= ALL (SELECT * FROM t1);
DROP TABLE t1;
--echo #
--echo # MDEV-32148 Inefficient WHERE timestamp_column=datetime_expr
--echo #
--echo #
--echo # Testing a DST change (fall back)
--echo #
SET time_zone='Europe/Moscow';
# '2010-10-31 02:59:59' (1288479599)
# '2010-10-31 02:00:00' (1288479600)
SET @first_second_after_dst_fall_back=1288479600;
CREATE TABLE t1 (a TIMESTAMP NULL);
INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31');
--echo #
--echo # Optimized (more than 24 hours before the DST fall back)
--echo #
SET timestamp=@first_second_after_dst_fall_back-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (24 hours before the DST fall back)
--echo #
SET timestamp=@first_second_after_dst_fall_back-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (less than 24 hours after the DST fall back)
--echo #
SET timestamp=@first_second_after_dst_fall_back+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Optimized (24 hours after the DST fall back)
--echo #
SET timestamp=@first_second_after_dst_fall_back+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
DROP TABLE t1;
SET time_zone=DEFAULT;
--echo #
--echo # Testing a DST change (spring forward)
--echo #
SET time_zone='Europe/Moscow';
# '2011-03-27 01:59:59' (1301180399)
# '2011-03-27 03:00:00' (1301180400)
SET @first_second_after_dst_spring_forward=1301180400;
CREATE TABLE t1 (a TIMESTAMP NULL);
INSERT INTO t1 VALUES ('2001-01-01 10:20:30'),('2001-01-01 10:20:31');
--echo #
--echo # Optimized (more than 24 hours before the DST sprint forward)
--echo #
SET timestamp=@first_second_after_dst_spring_forward-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (24 hours before the DST sprint forward)
--echo #
SET timestamp=@first_second_after_dst_spring_forward-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (less than 24 hours after the DST sprint forward)
--echo #
SET timestamp=@first_second_after_dst_spring_forward+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Optimized (24 hours after the DST sprint forward)
--echo #
SET timestamp=@first_second_after_dst_spring_forward+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
DROP TABLE t1;
--echo #
--echo # Testing a leap second
--echo #
SET time_zone='leap/Europe/Moscow';
SET @leap_second=362793609; /*The 60th leap second*/
CREATE TABLE t1 (a TIMESTAMP);
SET timestamp=@leap_second-1;
INSERT INTO t1 VALUES (NOW());
SET timestamp=@leap_second;
INSERT INTO t1 VALUES (NOW());
SET timestamp=@leap_second+1;
INSERT INTO t1 VALUES (NOW());
SELECT UNIX_TIMESTAMP(a), a FROM t1 ORDER BY UNIX_TIMESTAMP(a);
INSERT INTO t1 VALUES ('2001-01-01 10:20:30');
--echo #
--echo # Optimized (more than 24 hours before the leap second)
--echo #
SET timestamp=@leap_second-24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (24 hours before the leap second)
--echo #
SET timestamp=@leap_second-24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (less than 24 hours after the leap second)
--echo #
SET timestamp=@leap_second+24*3600-1;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
--echo #
--echo # Not optimized (24 hours after the leap second)
--echo #
SET timestamp=@leap_second+24*3600;
SELECT UNIX_TIMESTAMP(), NOW();
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=now();
DROP TABLE t1;
SET time_zone=DEFAULT;