1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +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

@@ -1207,6 +1207,63 @@ void thd_gmt_sec_to_TIME(MYSQL_THD thd, MYSQL_TIME *ltime, my_time_t t)
}
/*
@brief
Convert a non-zero DATETIME to its safe timeval based representation,
which guarantees a safe roundtrip DATETIME->timeval->DATETIME,
e.g. to optimize:
WHERE timestamp_arg0 = datetime_arg1
in the way that we replace "datetime_arg1" to its TIMESTAMP equivalent
"timestamp_arg1" and switch from DATETIME comparison to TIMESTAMP comparison:
WHERE timestamp_arg0 = timestamp_arg1
This helps to avoid slow TIMESTAMP->DATETIME data type conversion
for timestamp_arg0 per row.
@detail
Round trip is possible if the input "YYYY-MM-DD hh:mm:ss" value
satisfies the following conditions:
1. TIME_to_gmt_sec() returns no errors or warnings,
which means the input value
a. has no zeros in YYYYMMDD
b. fits into the TIMESTAMP range
c. does not fall into the spring forward gap
(because values inside gaps get adjusted to the beginning of the gap)
2. The my_time_t value returned by TIME_to_gmt_sec() must not be
near a DST change or near a leap second, to avoid anomalies:
- "YYYY-MM-DD hh:mm:ss" has more than one matching my_time_t values
- "YYYY-MM-DD hh:mm:ss" has no matching my_time_t values
(e.g. fall into the spring forward gap)
@param dt The DATETIME value to convert.
Must not be zero '0000-00-00 00:00:00.000000'.
(The zero value must be handled by the caller).
@return The conversion result
@retval If succeeded, non-NULL Timeval value.
@retval Timeval_null value representing SQL NULL if the argument
does not have a safe replacement.
*/
Timeval_null
THD::safe_timeval_replacement_for_nonzero_datetime(const Datetime &dt)
{
used|= THD::TIME_ZONE_USED;
DBUG_ASSERT(non_zero_date(dt.get_mysql_time()));
uint error= 0;
const MYSQL_TIME *ltime= dt.get_mysql_time();
my_time_t sec= variables.time_zone->TIME_to_gmt_sec(ltime, &error);
if (error /* (1) */ ||
!variables.time_zone->is_monotone_continuous_around(sec) /* (2) */)
return Timeval_null();
return Timeval_null(sec, ltime->second_part);
}
#ifdef _WIN32
extern "C" my_thread_id next_thread_id_noinline()
{