简体   繁体   English

如何重写SQL查询以在MariaDB和MySQL上实现相同的性能

[英]How to rewrite a SQL query to achieve the same performance on MariaDB and MySQL

Nowadays you read often 'MariaDB is a drop in replacement for MySQL'. 如今,您经常读到“ MariaDB是MySQL的替代品”。 But in reality there are sometimes huge differences. 但实际上,有时会存在巨大差异。 Eg this one: 例如:

There is an application using a query with MariaDB which performs well. 有一个使用MariaDB查询的应用程序运行良好。 Now MySQL must be used and surprisingly the performance is inadequate. 现在必须使用MySQL,而且令人惊讶的是性能不足。

How can I achieve the same performance on MySQL? 如何在MySQL上达到相同的性能?

  • Am I missing any setting? 我是否缺少任何设置? With mariadb it's running fast out of the box. 使用mariadb,它可以快速运行。
  • Should I modify the query? 我应该修改查询吗?
  • And what's the best query then? 那么最好的查询是什么?

The query determines the current value and the value one year ago, but there is not a value for every day, so the closest date to one-year-ago is searched. 该查询确定当前值和一年前的值,但是每天没有一个值,因此将搜索距一年前最近的日期。

Here is the query . 这是查询 Code to create some test data is below. 下面是创建一些测试数据的代码。

SELECT c.id, c.nname as n, a.wert as x,
(SELECT z.wert FROM tbl_history z
 WHERE z.indize_id = a.indize_id
 AND z.hdate > DATE_SUB(a.hdate, INTERVAL 1 YEAR)
 ORDER BY z.hdate LIMIT 1
) as y
FROM tbl_history a
LEFT JOIN tbl_indize c ON a.indize_id = c.id
WHERE a.hdate = 
(SELECT b.hdate FROM tbl_history b
 WHERE b.indize_id = a.indize_id ORDER BY b.hdate DESC LIMIT 1)
AND a.indize_id = 1;

Execution time on 执行时间

  • MariaDB: 0.01s MariaDB:0.01秒
  • MySQL: 12.23s MySQL的:12.23秒

And here some dummy data to play with 这是一些虚拟数据

CREATE TABLE tbl_indize (
  id int(11) NOT NULL AUTO_INCREMENT,
  nname varchar(145) NOT NULL,
  PRIMARY KEY (id)
);

CREATE TABLE tbl_history (
  id int(11) NOT NULL AUTO_INCREMENT,
  indize_id int(11) NOT NULL,
  hdate date NOT NULL,
  wert decimal(18,6) DEFAULT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY idx_id_date (indize_id,hdate)
);

INSERT INTO tbl_indize (nname) values ('test');

INSERT INTO tbl_history (indize_id, hdate, wert) values (1, '1970-01-01', RAND());
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 4096 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 2048 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 1024 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 512 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 256 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 128 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 64 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 32 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 16 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 8 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 4 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 2 DAY), SQRT(wert * RAND()) FROM tbl_history;
INSERT INTO tbl_history (indize_id, hdate, wert) SELECT indize_id, date_add(hdate, INTERVAL 1 DAY), SQRT(wert * RAND()) FROM tbl_history;
DELETE FROM tbl_history WHERE DAYOFWEEK(hdate) = 1;
DELETE FROM tbl_history WHERE DAYOFWEEK(hdate) = 2;

Here are the explains 这是解释

MariaDB 玛丽亚数据库

+------+--------------------+-------+-------+---------------+-------------+---------+---------------+------+------------------------------------+
| id   | select_type        | table | type  | possible_keys | key         | key_len | ref           | rows | Extra                              |
+------+--------------------+-------+-------+---------------+-------------+---------+---------------+------+------------------------------------+
|    1 | PRIMARY            | a     | ALL   | idx_id_date   | NULL        | NULL    | NULL          | 5877 | Using where                        |
|    1 | PRIMARY            | c     | const | PRIMARY       | PRIMARY     | 4       | const         |    1 |                                    |
|    3 | DEPENDENT SUBQUERY | b     | ref   | idx_id_date   | idx_id_date | 4       | t.a.indize_id | 2938 | Using where; Using index           |
|    2 | DEPENDENT SUBQUERY | z     | ref   | idx_id_date   | idx_id_date | 4       | t.a.indize_id | 2938 | Using index condition; Using where |
+------+--------------------+-------+-------+---------------+-------------+---------+---------------+------+------------------------------------+

MySQL 的MySQL

+----+--------------------+-------+------------+-------+---------------+-------------+---------+---------------+------+----------+------------------------------------------+
| id | select_type        | table | partitions | type  | possible_keys | key         | key_len | ref           | rows | filtered | Extra                                    |
+----+--------------------+-------+------------+-------+---------------+-------------+---------+---------------+------+----------+------------------------------------------+
|  1 | PRIMARY            | a     | NULL       | ALL   | idx_id_date   | NULL        | NULL    | NULL          | 5877 |    99.57 | Using where                              |
|  1 | PRIMARY            | c     | NULL       | const | PRIMARY       | PRIMARY     | 4       | const         |    1 |   100.00 | NULL                                     |
|  3 | DEPENDENT SUBQUERY | b     | NULL       | ref   | idx_id_date   | idx_id_date | 4       | t.a.indize_id |    1 |   100.00 | Using where; Using index; Using filesort |
|  2 | DEPENDENT SUBQUERY | z     | NULL       | ref   | idx_id_date   | idx_id_date | 4       | t.a.indize_id |    1 |    33.33 | Using index condition; Using filesort    |
+----+--------------------+-------+------------+-------+---------------+-------------+---------+---------------+------+----------+------------------------------------------+

After playing around, I found an improvement: 玩了之后,我发现了一个改进:

SELECT c.id, c.nname as n, a.wert as x,
(SELECT z.wert FROM tbl_history z
 WHERE z.indize_id = a.indize_id
 AND z.hdate > DATE_SUB(a.hdate, INTERVAL 1 YEAR)
 ORDER BY z.hdate LIMIT 1
) as y
FROM tbl_history a
LEFT JOIN tbl_indize c ON a.indize_id = c.id
LEFT JOIN (SELECT MAX(hdate) as d, indize_id FROM tbl_history GROUP BY indize_id) x
ON x.indize_id = a.indize_id
WHERE a.hdate = x.d
AND a.indize_id = 1;

And now the speed is ok on both databases. 现在两个数据库的速度都可以。

  • MariaDB: 0.00s MariaDB:0.00秒
  • MySQL: 0.00s MySQL:0.00秒

Well - very compatible ^^ 好吧-非常兼容^^

Basic Recipe 基本食谱

Replace sub-selects in the where clause with join-selects. 将where子句中的子选择替换为join-selects。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM