Разный план объяснения в том же кластере

У меня проблема с этим запросом:

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;

У нас есть кластер с сервером percona (5.6.29) с 5 узлами (от 0 до 4) в Azure. Разница между узлами 0-3 и 4 заключается в том, что первые из них находятся в балансировке, а node 4 выходит из балансира (но в кластере)

Проблема заключается в том, что на четырех серверах (узлы 0-3) запрос выполняется очень медленно (15 секунд), а в другом (node 4) запрос выполняется очень быстро (0,002)

Afaik, план объяснения должен быть таким же, но я выполняю 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                           |
+----+-------------+-------+------+-------------------------------------------------------------+--------------+---------+-------------------------------+---------+---------------------------------------+

Node 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                  |
+----+-------------+-------+--------+-------------------------------------------------------------+---------------------------------+---------+-----------------------------------+---------+-----------------------+

Я заметил, что в медленном индексе не используется. поэтому я проверил индексы:

Node 0:

+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| 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      |         |               |
+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

Node 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         |     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      |         |               |
+-----------------+------------+----------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

Мой первый вопрос - почему разные индексы? это должно быть одинаково из-за того, что оба находятся в одном кластере правильно?

Почему планы выполнения отличаются? Оба находятся в одном кластере, поэтому он должен быть тем же самым

Должен ли я использовать FORCE INDEX или STRAIGHT_JOIN?

Ответ 1

Ответ скрыт в двух объясняемых выводах - на node 4, второе соединение использует индекс is_validated_with в таблице uca, но ожидаемое количество строк - 2755595, что больше, чем количество строк для полного сканирования таблицы uc на другом плане.

С доступной информацией это трудно сказать наверняка, но поскольку узлы 0-3 видят активное использование, а node4 - нет, я предполагаю, что статистика, которую оптимизатор использует для определения планов запросов, может больше не отражать фактическое состояние таблицы. Вы можете попытаться запустить ANALYZE TABLE во всех трех таблицах на всех узлах, и я подозреваю, что вы увидите тот же самый сгенерированный план (при условии, что все узлы имеют одинаковые данные).

В дополнение к использованию FORCE_INDEX вы также можете настроить флаги оптимизатора, чтобы попытаться поддержать один план над другим, но в целом он лучше исправить основную проблему, поскольку теперь вы можете решить эту проблему только для того, чтобы потом укусить что-то еще.

Ответ 2

Я думаю, что у вас есть поле 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;