MySQL index_merge 导致查询运行速度减慢 10 倍

标签 mysql database optimization indexing merge

我有一个具有以下属性的表:

+-----------------------+--------------+------+-----+---------+----------------+
| Field                 | Type         | Null | Key | Default | Extra          |
+-----------------------+--------------+------+-----+---------+----------------+
| id                    | int(11)      | NO   | PRI | <null>  | auto_increment |
| c2                    | varchar(255) | YES  | MUL | <null>  |                |
| c3                    | int(11)      | YES  |     | <null>  |                |
| c4                    | varchar(255) | YES  |     | <null>  |                |
| c5                    | varchar(255) | YES  |     | <null>  |                |
| c6                    | int(11)      | YES  | MUL | <null>  |                |
| c7                    | int(11)      | YES  |     | <null>  |                |
| c8                    | int(11)      | YES  |     | <null>  |                |
| c9                    | datetime     | YES  |     | <null>  |                |
| c10                   | datetime     | YES  |     | <null>  |                |
| c11                   | char(40)     | YES  | UNI | <null>  |                |
| c12                   | tinyint(1)   | NO   | MUL | 1       |                |
| c13                   | text         | YES  |     | <null>  |                |
| c14                   | int(11)      | YES  | MUL | <null>  |                |
| c15                   | varchar(64)  | YES  | MUL | <null>  |                |
+-----------------------+--------------+------+-----+---------+----------------+

显示 table_one 的索引; 显示以下输出:

+-------------------+------------+--------------------------------------------------+--------------+-----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table             | Non_unique | Key_name                                         | Seq_in_index | Column_name           | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------------------+------------+--------------------------------------------------+--------------+-----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| table_one         |          0 | PRIMARY                                          |            1 | id                    | A         |     1621972 |     NULL | NULL   |      | BTREE      |         |               |
| table_one         |          0 | c11                                              |            1 | c11                   | A         |     1621972 |     NULL | NULL   | YES  | BTREE      |         |               |
| table_one         |          0 | c2_c6_c8_and_c14_unique                          |            1 | c2                    | A         |     1621972 |     NULL | NULL   | YES  | BTREE      |         |               |
| table_one         |          0 | c2_c6_c8_and_c14_unique                          |            2 | c6                    | A         |     1621972 |     NULL | NULL   | YES  | BTREE      |         |               |
| table_one         |          0 | c2_c6_c8_and_c14_unique                          |            3 | c8                    | A         |     1621972 |     NULL | NULL   | YES  | BTREE      |         |               |
| table_one         |          0 | c2_c6_c8_and_c14_unique                          |            4 | c14                   | A         |     1621972 |     NULL | NULL   | YES  | BTREE      |         |               |
| table_one         |          1 | c12                                              |            1 | c12                   | A         |           1 |     NULL | NULL   |      | BTREE      |         |               |
| table_one         |          1 | c6                                               |            1 | c6                    | A         |       20794 |     NULL | NULL   | YES  | BTREE      |         |               |
| table_one         |          1 | c14                                              |            1 | c14                   | A         |         577 |     NULL | NULL   | YES  | BTREE      |         |               |
| table_one         |          1 | c15                                              |            1 | c15                   | A         |           5 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------------------+------------+--------------------------------------------------+--------------+-----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

现在,当我运行以下查询时,平均需要大约 5.8 秒:

select * from table_one
    where c6 = 12345 and c14 = 12
    limit 10 offset 0;

当我对上面的查询运行explain时,它说它已经使用了index_merge:

+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+------+-------------------------+
| id | select_type | table               | type        | possible_keys               | key     | key_len | ref                           | rows | Extra                   |
+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+------+-------------------------+
|  1 | SIMPLE      | table_one           | index_merge | .......................     | c14, c6 | 5,5     | NULL                          |    9 | Using intersect(c14,c6);|
+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+------+-------------------------+

但是,如果我强制表仅在 c6 上使用索引,它会平均在 0.6 秒内返回结果:

select * from table_one force index(c6) where c6 = 12345 and c14 = 12 limit 10 offset 0;

为什么 MySQL 单独使用 index_merge 并使其变慢?我知道我在 c6、c14 上没有复合索引,但它们单独存在。

此外,强制索引的 explain 查询显示执行查询时访问的行数更多,但速度仍然快了 10 倍。

+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+--------+-------------------------+
| id | select_type | table               | type        | possible_keys               | key     | key_len | ref                           | rows   | Extra                   |
+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+--------+-------------------------+
|  1 | SIMPLE      | table_one           | ref         | .......................     | c6      | 5       | const                         | 22388  | Using where;            |
+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+--------+-------------------------+

当有人高速访问 API 时,这会导致我们的生产量下降。 MySQL 在 59 秒内没有返回任何结果,查询超时。

另外,我无法在不停机的情况下真正添加复合索引或更改架构,因为我们已经有 200 万个条目。

当前的临时修复是将强制索引(c6)添加到查询中,但我不太确定它的可扩展性如何,或者我们以后是否可能会遇到问题。

编辑 1 缓慢是否是由于 index_merge 完成的顺序造成的?

有关 c6c14 的更多信息:将 c6 视为国家/地区,将 c14 视为州。

编辑 2:2020-06-15 07:52:35 UTC: 我尝试通过强制 c14 的索引来运行查询,结果慢了大约 3 倍:

select * from table_one force index(c14) where c6 = 12345 and c14 = 12 limit 10 offset 0;

查询花费了 2.1 秒。

explain 查询给出以下输出:

+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+--------+-------------------------+
| id | select_type | table               | type        | possible_keys               | key     | key_len | ref                           | rows   | Extra                   |
+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+--------+-------------------------+
|  1 | SIMPLE      | table_one           | ref         | .......................     | c14     | 5       | const                         | 730    | Using where;            |
+----+-------------+---------------------+-------------+-----------------------------+---------+---------+-------------------------------+--------+-------------------------+

查询要访问的行数比在 c6 上强制索引时少了 30 倍。即,这里的行数为 730,而对于上一个查询,行数为 22k。即使访问的行数较少,哪些因素也会使该索引变慢?

更多信息(如果有任何帮助的话):

mysql> select count(*) from table_one where c14 is null;
+----------+
| count(*) |
+----------+
|     7490 |
+----------+
1 row in set (0.02 sec)

mysql> select count(*) from table_one;
+----------+
| count(*) |
+----------+
|  1936278 |
+----------+
1 row in set (1.68 sec)

mysql> select count(*) from table_one where c6 is null;
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (0.00 sec)

最佳答案

考虑 使用(数据库名称); 更改表 table_one 添加索引 table_one_c6_and_c14 (c6,c14);

删除查询中的强制请求。

请告诉我们创建多列索引需要多长时间。 既然有合适的索引可用,就到了完成查询的时间了。

关于MySQL index_merge 导致查询运行速度减慢 10 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62364544/

相关文章:

mysql - 在 MySQL 表中查找 "exotic"值

php 表单将 < 符号转换为 <

java - 如何将结果集的所有行返回给客户端?

c++ - 使用 move 语义优化二进制算术运算

mysql查询从一张表中合并表

mysql - Rails 不会在测试数据库中重新创建 mysql View ,即使 config.active_record.schema_format = :sql

mysql - 'WHERE column LIKE "%expression %"' 如何在 MySQL 中比 MATCH(column) AGAINST ("expression") 表现得更好?

iPhone 当应用程序升级到新版本时,以前的数据会发生什么

ruby-on-rails - 数据库 - 动态表选择

python - scipy 最小化 SLSQP - 'Singular matrix C in LSQ subproblem'