[MDEV-23551] Performance degratation in temporal literals in 10.4 Created: 2020-08-24  Updated: 2020-10-06  Resolved: 2020-08-24

Status: Closed
Project: MariaDB Server
Component/s: Data types, Temporal Types
Affects Version/s: 10.4, 10.5
Fix Version/s: 10.4.16, 10.5.7

Type: Bug Priority: Major
Reporter: Alexander Barkov Assignee: Alexander Barkov
Resolution: Fixed Votes: 0
Labels: benchmarking

Issue Links:
Relates
relates to MDEV-23525 Wrong result of MIN(time_expr) and MA... Closed
relates to MDEV-23537 Comparison with temporal columns is s... Closed

 Description   

Queries like these demonstrate performance degatation in 10.4 over 10.3:

SELECT temporal_literal FROM t1;
SELECT temporal_literal + 1 FROM t1;
SELECT COUNT(*) FROM t1 WHERE temporal_column = temporal_literal;
SELECT COUNT(*) FROM t1 WHERE temporal_column = string_literal;

Also, 10.4 is slower than MySQL-8.0 (tested againts MySQL-8.0.21).

The problem happens because of excessive Time(), Date(), Datetime() instantiation in value methods.
For example:

Item_date_literal
{
  ..
  longlong val_int() { return Date(this).to_longlong(); }
  double val_real() { return Date(this).to_double(); }
  String *val_str(String *to) { return Date(this).to_string(to); }
  my_decimal *val_decimal(my_decimal *to) { return Date(this).to_decimal(to); }
};

Notice, the Date() instance is created in every value method call.
This involves copying from MYSQL_TIME in Item_temporal_literal::cached_time to MYSQL_TIME inside Date().

Changing the universal member Item_temporal_literal::cached_time to data type specific members and using them directly solve the problem:

class Item_date_literal
{
  Date cached_time;
public:
  longlong val_int() { ... return cached_time.to_longlong(); }
  double val_real() { ... return cached_time.to_double(); }
  String *val_str(String *to) { ... return cached_time.to_string(to); }
  my_decimal *val_decimal(my_decimal *to) { ...return cached_time.to_decimal(to); }
};

Notice, there is no copying any more.

Also, this change makes futher separations of Date, Time, Datetime from each other, which will make it possible not to derive them from MYSQL_TIME, which is too heavy (40 bytes), and replace them to smaller data type specific containers.

Benchmarks

The numbers below are query time in seconds: the smaller - the better.

Tested against the following RelWithDebInfo binaries:

My80              - MySQL-8.0.21,     commit f8cdce86448a211511e8a039c62580ae16cb96f5
10.3              - MariaDB 10.3.25,  commit 90c8d773ed0ea7de5e735e836e1e33a190711f17
10.4 (orig)       - MariaDB 10.4.15,  commit aa6cb7ed03bb41b7ba59b6d7c9197cf24d65a36d
10.4 (MDEV-23537) - MariaDB 10.4.15,  commit 2e5d86f49e7ee538806fba68dc8c960d6acdd483
10.4 (fixed)      - MariaDB 10.4.15,  the current patch on top of MDEV-23537

Benchmark preparation:

### t3 is a table with 10 rows
### t2 is a table with 1000 rows
### t1 is a HEAP table created per test, with 1000*1000 rows
 
DROP TABLE IF EXISTS t3,t2;
CREATE TABLE t3 (a INT);
INSERT INTO t3 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
CREATE TABLE t2 AS SELECT 1 FROM t3 t3a, t3 t3b, t3 t3c;

datetime_literal

SELECT BENCHMARK(10*1000*1000, TIMESTAMP'2001-01-01 10:20:30');

My80: 0.035 -- MySQL caches string representation
10.3: 0.218
10.4: 0.268 (orig)
10.4: 0.275 (MDEV-23537)         ???
10.4: 0.123 (fixed)

datetime_literal + 1

SELECT BENCHMARK(10*1000*1000, TIMESTAMP'2001-01-01 10:20:30'+1);

My80: 0.160
10.3: 0.190
10.4: 0.218 (orig)
10.4: 0.222 (MDEV-23537)          ???
10.4: 0.084 (fixed)

datetime_column = string_constant

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a DATETIME DEFAULT '2001-01-01 10:20:30') ENGINE=HEAP;
INSERT INTO t1 SELECT '2001-01-01 10:20:30' FROM t2,t2 t2a;
SELECT COUNT(*) FROM t1 WHERE a='2001-01-01 10:20:30';

My80:  0.035
10.3:  0.049
10.4:  0.049 (orig)
10.4:  0.043 (MDEV-23537)
10.4:  0.035 (fixed)

datetime_column = datetime_literal

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a DATETIME DEFAULT '2001-01-01 10:20:30') ENGINE=HEAP;
INSERT INTO t1 SELECT '2001-01-01 10:20:30' FROM t2,t2 t2a;
SELECT COUNT(*) FROM t1 WHERE a=TIMESTAMP'2001-01-01 10:20:30';

My80:  0.035
10.3:  0.053
10.4:  0.056 (orig)
10.4:  0.046 (MDEV-23537)
10.4:  0.035 (fixed)

time_literal

SELECT BENCHMARK(10*1000*1000, TIME'10:20:30');

My80: 0.035 -- MySQL caches string representation
10.3: 0.126
10.4: 0.132 (orig)
10.4: 0.136 (MDEV-23537)  ???
10.4: 0.085 (fixed)

time_literal + 1

SELECT BENCHMARK(10*1000*1000, TIME'10:20:30'+1);

My80: 0.114
10.3: 0.146
10.4: 0.135 (orig)
10.4: 0.135 (MDEV-23537)
10.4: 0.085 (fixed)

time_column = string_constant

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a TIME) ENGINE=HEAP;
INSERT INTO t1 SELECT '10:20:30' FROM t2,t2 t2a;
SELECT COUNT(*) FROM t1 WHERE a='10:20:30';

My80: 0.034
10.3: 0.038
10.4: 0.046 (orig)
10.4: 0.041 (MDEV-23537)
10.4: 0.034 (fixed)

time_column = time_literal

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a TIME) ENGINE=HEAP;
INSERT INTO t1 SELECT '10:20:30' FROM t2,t2 t2a;
SELECT COUNT(*) FROM t1 WHERE a=TIME'10:20:30';

My80: 0.035
10.3: 0.038
10.4: 0.046 (orig)
10.4: 0.040 (MDEV-23537)
10.4: 0.035 (fixed)

date_literal

SELECT BENCHMARK(10*1000*1000, DATE'2001-01-01');

My80: 0.037 -- MySQL caches string representation
10.3: 0.181
10.4: 0.207 (orig)
10.4: 0.209 (MDEV-23537)   ???
10.4: 0.083 (fixed)

date_literal + 1

SELECT BENCHMARK(10*1000*1000, DATE'2001-01-01'+1);

My80: 0.131
10.3: 0.189
10.4: 0.201 (orig)
10.4: 0.201 (MDEV-23537)
10.4: 0.079 (fixed)

date_column = string_constant

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a DATE) ENGINE=HEAP;
INSERT INTO t1 SELECT '2001-01-01' FROM t2,t2 t2a;
SELECT COUNT(*) FROM t1 WHERE a='2001-01-01';

My80: 0.038
10.3: 0.045
10.4: 0.045 (orig)
10.4: 0.040 (MDEV-23537)
10.4: 0.034 (fixed)

date_column = date_literal

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a DATE) ENGINE=HEAP;
INSERT INTO t1 SELECT '2001-01-01' FROM t2,t2 t2a;
SELECT COUNT(*) FROM t1 WHERE a=DATE'2001-01-01';

My80: 0.036
10.3: 0.051
10.4: 0.050 (orig)
10.4: 0.044 (MDEV-23537)
10.4: 0.035 (fixed)


Generated at Thu Feb 08 09:23:15 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.