同一集群中不同的执行计划

12

我有一个问题与这个查询相关:

SELECT 
    uca.user_activity_id,
    uca.user_call_id,
    uca.call_activity_id,
    uca.user_activity_token,
    uc.call_group_id,
    uc.user_id
FROM users_calls_activities uca
INNER JOIN users_calls_activities uca2 ON uca2.user_activity_id = uca.user_activity_is_validated_with
    AND aux.user_call_id = 1744136
INNER JOIN users_calls uc ON uc.user_call_id = uca.user_call_id;

我们在Azure上拥有一个使用percona server(5.6.29)的集群,共有5个节点(从0到4)。其中0-3号节点在负载均衡器中,而第4个节点虽然在集群中,但不在负载均衡器中。

问题是,在前四台服务器中(0-3号节点),查询速度非常慢(15秒),而在另一台服务器中(4号节点),查询速度非常快(0.002秒)。

据我所知,查询计划应该是相同的,但我执行了EXPLAIN命令,结果如下:

0-3号节点(慢)

+----+-------------+-------+------+-------------------------------------------------------------+--------------+---------+-------------------------------+---------+---------------------------------------+
| id | select_type | table | type | possible_keys                                               | key          | key_len | ref                           | rows    | Extra                                 |
+----+-------------+-------+------+-------------------------------------------------------------+--------------+---------+-------------------------------+---------+---------------------------------------+
|  1 | SIMPLE      | uca2  | ref  | PRIMARY,user_call_id,user_call_id_2                         | user_call_id | 4       | const                         |       1 | Using index                           |
|  1 | SIMPLE      | uc    | ALL  | PRIMARY,user_call_id                                        | NULL         | NULL    | NULL                          | 2098152 | Using join buffer (Block Nested Loop) |
|  1 | SIMPLE      | uca   | ref  | user_call_id,user_call_id_2,is_validated_with               | user_call_id | 4       | db.uc.user_call_id            |       1 | Using where                           |
+----+-------------+-------+------+-------------------------------------------------------------+--------------+---------+-------------------------------+---------+---------------------------------------+

4号节点(快)

+----+-------------+-------+--------+-------------------------------------------------------------+---------------------------------+---------+-----------------------------------+---------+-----------------------+
| id | select_type | table | type   | possible_keys                                               | key                             | key_len | ref                               | rows    | Extra                 |
+----+-------------+-------+--------+-------------------------------------------------------------+---------------------------------+---------+-----------------------------------+---------+-----------------------+
|  1 | SIMPLE      | uca2  | ref    | PRIMARY,user_call_id,user_call_id_2                         | user_call_id                    | 4       | const                             |       1 | Using index           |
|  1 | SIMPLE      | uca   | ref    | user_call_id,user_call_id_2,is_validated_with               | is_validated_with               | 5       | db.uc2.user_activity_id           | 2755595 | Using index condition |
|  1 | SIMPLE      | uc    | eq_ref | PRIMARY,user_call_id                                        | PRIMARY                         | 4       | db.uca.user_call_id               |       1 | NULL                  |
+----+-------------+-------+--------+-------------------------------------------------------------+---------------------------------+---------+-----------------------------------+---------+-----------------------+

我注意到在慢的那个查询计划中没有使用索引,所以我检查了索引:

节点 4:

+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table           | Non_unique | Key_name             | Seq_in_index | Column_name          | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| users_calls     |          0 | PRIMARY              |            1 | user_call_id         | A         |     2099153 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | call_group_id        |            1 | call_group_id        | A         |       16659 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_call_begin_date |            1 | user_call_begin_date | A         |     1049576 |     NULL | NULL   | YES  | BTREE      |         |               |
| users_calls     |          1 | user_call_begin_date |            2 | user_call_end_date   | A         |     2099153 |     NULL | NULL   | YES  | BTREE      |         |               |
| users_calls     |          1 | user_call_id         |            1 | user_call_id         | A         |     2099153 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_call_id         |            2 | user_id              | A         |     2099153 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_id              |            1 | user_id              | A         |       91267 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_id              |            2 | call_id              | A         |     2099153 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_id              |            3 | user_call_status     | A         |     2099153 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | fk_users_calls_calls |            1 | call_id              | A         |       23067 |     NULL | NULL   |      | BTREE      |         |               |
+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| 表              | 非唯一     | 键名                 | 索引序列     | 列名                 | 排序规则  | 基数        | 子集    | 压缩   | 空值 | 索引类型   | 注释    | 索引注释      |
+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| users_calls     |          0 | PRIMARY              |            1 | user_call_id         | A         |     2091476 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | call_group_id        |            1 | call_group_id        | A         |       26813 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_call_begin_date |            1 | user_call_begin_date | A         |     1045738 |     NULL | NULL   | YES  | BTREE      |         |               |
| users_calls     |          1 | user_call_begin_date |            2 | user_call_end_date   | A         |     2091476 |     NULL | NULL   | YES  | BTREE      |         |               |
| users_calls     |          1 | user_call_id         |            1 | user_call_id         | A         |     2091476 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_call_id         |            2 | user_id              | A         |     2091476 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_id              |            1 | user_id              | A         |       53627 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_id              |            2 | call_id              | A         |     2091476 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | user_id              |            3 | user_call_status     | A         |     2091476 |     NULL | NULL   |      | BTREE      |         |               |
| users_calls     |          1 | fk_users_calls_calls |            1 | call_id              | A         |       15608 |     NULL | NULL   |      | BTREE      |         |               |
+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
问题1:为什么索引不同?因为它们使用了不同的列或列组合作为索引,索引可以根据查询需求来创建。
问题2:为什么执行计划不同?执行计划取决于查询条件和优化器的选择,即使在同一集群中,也可能会有不同的性能表现。
问题3:应该使用FORCE INDEX还是STRAIGHT_JOIN?这取决于数据大小、查询条件和优化器实现,建议进行基准测试来确定哪种方法更有效。

user_calls_activities 的索引是什么,is_validated_with 似乎在该表中。 - Andrew Mackrodt
2个回答

1
答案隐藏在两个解释输出中-在节点4上,第二个连接使用了uca表上的is_validated_with索引,但预期的行数为2755595,这比另一个计划上uc表的全扫描行数要大。
根据可用信息很难确定,但由于节点0-3正在活跃使用,而节点4没有使用,我猜测优化器用于决定查询计划的统计信息可能不再反映表的实际状态。您可以尝试在所有节点上对三个表运行ANALYZE TABLE,我怀疑您会看到生成相同计划(假设所有节点具有相同数据)。
除了使用FORCE_INDEX外,您还可以调整优化器标志以尝试支持一个计划而不是另一个,但通常更好的方法是修复潜在问题,因为您可能现在只能解决此问题,以后可能会遇到其他问题。

0

我认为你在两个表中都有user_call_id字段。如果你像这样更改查询,它将强制服务器使用索引:

SELECT 
    uca.user_activity_id,
    uca.user_call_id,
    uca.call_activity_id,
    uca.user_activity_token,
    uc.call_group_id,
    uc.user_id
FROM users_calls_activities uca
INNER JOIN users_calls_activities uca2 ON uca2.user_activity_id = uca.user_activity_is_validated_with AND uca2.user_call_id = 1744136
INNER JOIN users_calls uc ON uc.user_call_id = uca.user_call_id uc.user_call_id = 1744136
WHERE uca.user_call_id = 1744136;

抱歉回答晚了,但是你的建议不起作用,问题依旧。 - Sal00m

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接