【问题标题】:query extremely slow after migration to mysql 5.7迁移到 mysql 5.7 后查询极慢
【发布时间】:2016-06-09 18:48:34
【问题描述】:

我有一个 MySQL 数据库,其中 InnoDB 表汇总了超过 10 GB 的数据,我想从 MySQL 5.5 迁移到 MySQL 5.7。我有一个看起来有点像的查询:

SELECT dates.date, count(mySub2.myColumn1), sum(mySub2.myColumn2)
FROM (
    SELECT date
    FROM dates -- just a table containing all possible dates next 5 years
    WHERE date BETWEEN '2016-06-01' AND '2016-09-03'
) AS dates
LEFT JOIN (
    SELECT o.id, time_start, time_end
    FROM order AS o
    INNER JOIN order_items AS oi on oi.order_id = o.id
    WHERE time_start BETWEEN '2016-06-01' AND '2016-09-03'
) AS mySub1 ON dates.date >= mySub1.time_start AND dates.date < mySub1.time_end
LEFT JOIN (
    SELECT o.id, time_start, time_end
    FROM order AS o
    INNER JOIN order_items AS oi on oi.order_id = o.id
    WHERE o.shop_id = 50 AND time_start BETWEEN '2016-06-01' AND '2016-09-03'
) AS mySub2 ON dates.date >= mySub2.time_start AND dates.date < mySub2.time_end
GROUP BY dates.date;

我的问题是这个查询在 MySQL 5.5 中执行得很快,但在 MySQL 5.7 中却非常慢。

在 MySQL 5.5 中,它一开始需要超过 1 秒,每次重复执行需要 在 MySQL 5.7 中,它一开始需要 11.5 秒,每次重复执行需要 1.4 秒,而无需重新启动 MySQL。
在查询中添加的 LEFT JOIN 越多,MySQL 5.7 中的查询速度就越慢。

这两个实例现在运行在同一台机器上,在同一个硬盘驱动器上,并具有相同的 my.ini 设置。所以它不是硬件。
不过,执行计划确实不同,我不知道该怎么做。

这是 MySQL 5.5 上的 EXPLAIN EXTENDED:

| id | select_type | table      | type  | possible_keys | key         | key_len | ref       | rows  | filtered | extra                           |
|----|-------------|------------|-------|---------------|-------------|---------|-----------|-------|----------|---------------------------------|
| 1  | PRIMARY     | dates      | ALL   |               |             |         |           | 95    | 100.00   | Using temporary; Using filesort |
| 1  | PRIMARY     | <derived2> | ALL   |               |             |         |           | 281   | 100.00   | ''                              |
| 1  | PRIMARY     | <derived3> | ALL   |               |             |         |           | 100   | 100.00   | ''                              |
| 3  | DERIVED     | o          | ref   | xxxxxx        | shop_id_fk  | 4       | ''        | 1736  | 100.00   | ''                              |
| 3  | DERIVED     | oc         | ref   | xxxxx         | order_id_fk | 4       | myDb.o.id | 1     | 100.00   | Using index                     |
| 2  | DERIVED     | o          | range | xxxx          | date_start  | 3       |           | 17938 | 100.00   | Using where                     |
| 2  | DERIVED     | oc         | ref   | xxx           | order_id_fk | 4       | myDb.o.id | 1     | 100.00   | Using where                     |

这是 MySQL 5.7 上的 EXPLAIN EXTENDED:

| id | select_type | table | type   | possible_keys | key         | key_len | ref              | rows | filtered | extra          |
|----|-------------|-------|--------|---------------|-------------|---------|------------------|------|----------|----------------|
| 1  | SIMPLE      | dates | ALL    |               |             |         |                  | 95   | 100.00   | Using filesort |
| 1  | SIMPLE      | oi    | ref    | xxxxxx        | order_id_fk | 4       | const            | 228  | 100.00   |                |
| 1  | SIMPLE      | o     | eq_ref | xxxxx         | PRIMARY     | 4       | myDb.oi.order_id | 1    | 100.00   | Using where    |
| 1  | SIMPLE      | o     | ref    | xxxx          | shop_id_fk  | 4       | const            | 65   | 100.00   | Using where    |
| 1  | SIMPLE      | oi    | ref    | xxx           | order_id_fk | 4       | myDb.o.id        | 1    | 100.00   | Using where    |

我想了解为什么 MySQL 对同一个查询的处理会有如此大的不同,以及如何将 MySQL 5.7 调整得更快?
我不是在寻求帮助以更快地重写查询,因为这是我自己已经在做的事情。

【问题讨论】:

  • 只是为了确保... (1) 查询完全相同? (2)表,包括索引,完全一样吗?
  • @Uueerdo 是的,完全正确。起初它在不同的机器上。但是当我遇到这种情况时,我在笔记本电脑上同时安装了 MySQL 5.5 和 MySQL 5.7,并两次导入了相同的转储。我采用了相同的 my.ini 并对其进行了最少的更改,因此我可以一次运行这两个实例。所以一切都是一样的。然后我才对它们运行相同的查询。
  • 那我就不知道了。我的猜测是针对对这个特定(和特殊)查询产生负面影响的更常见的查询类型进行优化。
  • 查询计划会不会是无关的,而 MySQL 5.7 只是默认关闭了一些功能,例如某种键缓冲?
  • 优化器行为可能因版本而异,请检查每个服务器上的变量 optimizer_switch 5.55.7

标签: mysql database performance migration


【解决方案1】:

在 cmets 中可以看到,@wchiquito 建议查看 optimizer_switch。在这里,我发现开关 derived_merge 可以设置为关闭,以修复这个新的,在这种特定情况下不受欢迎的行为。

set session optimizer_switch='derived_merge=off'; 解决了这个问题。
(也可以用set global ...或者放在my.cnf/my.ini中)

【讨论】:

  • 您可以在以下文章中阅读更多内容:Derived Tables in MySQL 5.79.2.1.18 Subquery Optimization
  • 非常感谢。我有同样的情况,你的解决方案有效。就我而言,mysql-5.5 在 0.5 秒后返回结果,mysql-5.7 在 1.2 秒后返回结果。在禁用 derived_merge 优化器并将查询从连接重写为子查询 mysql-5.7 在 0.01s 后返回结果
  • 谢谢@nl-x。花了一整天的时间试图弄清楚为什么在旧的 MySQL 数据库服务器上花费 0.9 秒的查询在 MariaDB 服务器上花费了 4.5 分钟。关闭 'derived_merge' 标志将 MariaDB 查询的时间减少到 0.8 秒。有什么不同!如果性能影响如此之大,我不明白为什么这个标志默认为 ON。或者至少 MariaDB 应该为从 MySQL 切换的用户更好地记录它。
  • 完美!优秀的一个
  • @Ingus 我已将此添加到 my.cnf 并重新启动了 mysql。更改 --- [mysqld] sql_mode='' optimizer_switch='derived_merge=off,duplicateweedout=off'
【解决方案2】:

构建和维护“汇总表”将使该查询的运行速度比 1 秒快得多。

这样的表可能包括shop_iddate 和一些计数。

More on summary tables.

【讨论】:

    【解决方案3】:

    在迁移到 mysql 5.7 后,我也遇到了查询执行缓慢的问题,在我的情况下,甚至将 session optimizer_switch 设置为 'derived_merge=off';没有帮助。

    然后,我点击了这个链接:https://www.saotn.org/mysql-innodb-performance-improvement/,查询的速度变得正常了。

    具体来说,我的更改只是在 my.ini 中设置这四个参数,如链接中所述:

    innodb_buffer_pool_size

    innodb_buffer_pool_instances

    innodb_write_io_threads

    innodb_read_io_threads

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      • 2012-05-03
      • 1970-01-01
      • 2011-11-18
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      相关资源
      最近更新 更多