【问题标题】:MySQL query optimization with compound index and persistent column使用复合索引和持久列优化 MySQL 查询
【发布时间】:2018-12-11 21:35:59
【问题描述】:

以下查询正在 MariaDB 10.0.28 上运行,大约需要 17 秒,我希望大大加快速度。

select series_id,delivery_date,delivery_he,forecast_date,forecast_he,value 
from forecast where forecast_he=8 
AND series_id in (12142594,20735627,632287496,1146453088,1206342447,1154376340,2095084238,2445233529,2495523920,2541234725,2904312523,3564421486) 
AND delivery_date >= '2016-07-13' 
AND delivery_date < '2018-06-27' 
and DATEDIFF(delivery_date,forecast_date)=1

第一次尝试加速它是创建一个持久列作为 (datediff(delivery_date,forecast_date)),使用持久列重建索引,并修改查询,将 datediff calc 替换为 forecast_delivery_delta=1

> describe forecast;
+-------------------------+------------------+------+-----+---------+------------+
| Field                   | Type             | Null | Key | Default | Extra      |
+-------------------------+------------------+------+-----+---------+------------+
| series_id               | int(10) unsigned | NO   | PRI | 0       |            |
| delivery_date           | date             | NO   | PRI | NULL    |            |
| delivery_he             | int(11)          | NO   | PRI | NULL    |            |
| forecast_date           | date             | NO   | PRI | NULL    |            |
| forecast_he             | int(11)          | NO   | PRI | NULL    |            |
| value                   | float            | NO   |     | NULL    |            |
| forecast_delivery_delta | tinyint(4)       | YES  |     | NULL    | PERSISTENT |
+-------------------------+------------------+------+-----+---------+------------+

> show index from forecast;
+----------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name             | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| forecast |          0 | PRIMARY              |            1 | series_id     | A         |       35081 |     NULL | NULL   |      | BTREE      |         |               |
| forecast |          0 | PRIMARY              |            2 | delivery_date | A         |      130472 |     NULL | NULL   |      | BTREE      |         |               |
| forecast |          0 | PRIMARY              |            3 | delivery_he   | A         |     1290223 |     NULL | NULL   |      | BTREE      |         |               |
| forecast |          0 | PRIMARY              |            4 | forecast_date | A         |     2322401 |     NULL | NULL   |      | BTREE      |         |               |
| forecast |          0 | PRIMARY              |            5 | forecast_he   | A         |    23224016 |     NULL | NULL   |      | BTREE      |         |               |
| forecast |          1 | he_series_delta_date |            1 | forecast_he   | A         |       29812 |     NULL | NULL   |      | BTREE      |         |               |
| forecast |          1 | he_series_delta_date |            2 | series_id     | A         |       74198 |     NULL | NULL   |      | BTREE      |         |               |
| forecast |          1 | he_series_delta_date |            3 | delivery_date | A         |      774133 |     NULL | NULL   |      | BTREE      |         |               |
+----------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

这似乎使运行时间减少了约 2 秒,但我想知道是否有更好的方法可以大大加快速度。我考虑调整缓冲区大小,但似乎没有严重配置错误。

>show variables like '%innodb_buffer_pool_size%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| innodb_buffer_pool_size | 134217728 |
+-------------------------+-----------+


Total table size:
+----------+------------+
| Table    | Size in MB |
+----------+------------+
| forecast |    1547.00 |
+----------+------------+

EXPLAIN:
+------+-------------+----------+-------+------------------------------+----------------------+---------+------+--------+-----------------------+
| id   | select_type | table    | type  | possible_keys                | key                  | key_len | ref  | rows   | Extra                 |
+------+-------------+----------+-------+------------------------------+----------------------+---------+------+--------+-----------------------+
|    1 | SIMPLE      | forecast | range | PRIMARY,he_series_delta_date | he_series_delta_date | 11      | NULL | 832016 | Using index condition |
+------+-------------+----------+-------+------------------------------+----------------------+---------+------+--------+-----------------------+

【问题讨论】:

  • 你也可以发布来自 EXPLAIN “你的查询”
  • 我在帖子底部包含了 EXPLAIN 的结果。
  • 缓冲池大小为128MB,完全没有配置。这是默认值,意味着可以在笔记本电脑或最小尺寸的服务器上使用。对于任何生产服务器来说,这可能还不够。

标签: mysql sql indexing mariadb


【解决方案1】:

如果你要说

AND forecast_delivery_delta=1

那么最佳索引是一个 开始 与两个 = 列:

(forecast_he, forecast_delivery_delta,    -- in either order
 series_id,           -- an IN might work ok next
 delivery_date)       -- finally a range

将通过范围测试的列 (delivery_date) 放在除最后一个以外的任何位置通常是没有用的。

但请注意,如果您说 forecast_delivery_delta = 转换为范围,反之亦然。

并将innodb_buffer_pool_size 增加到大约 70% 的 RAM(假设您有超过 4GB 的 RAM)。

【讨论】:

  • 这将查询时间从 15 秒缩短到了 0.5 秒,而缓冲区大小没有任何变化。真的很有帮助,谢谢瑞克!
  • @dsclough - 从我的Index Cookbook 了解更多信息。
猜你喜欢
  • 1970-01-01
  • 2012-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多