スクリプトによってMySQLClusterに呼び出されるselectクエリがあります。これは、1〜2秒で実行されるのではなく、クエリごとに1分以上かかるようになりました(このクエリは24000回実行する必要があります)。前回の実行から数か月間、コードに関して何も変更されていません。私は適切なDBAではなく、長年のMySQLユーザーであり、key_cacheサイズの制限を超えてインデックスが問題になる可能性があることを別のスレッドで読みましたか?しかし、これはndbclusterテーブルタイプに適用されますか?もしそうなら、私はどのように言うでしょうか?
問題クエリのExplainの出力は次のとおりです。
EXPLAIN SELECT userid from users left outer join routes on routes.user_id = users.id left outer join aliases on aliases.route_id = routes.id where aliases.name='xxxx' and domain_id=8;
+----+-------------+---------+------+-----------------+----------+---------+------------------+--------+-----------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+-----------------+----------+---------+------------------+--------+-----------------------------------+
| 1 | SIMPLE | users | ALL | PRIMARY | NULL | NULL | NULL | 177802 | |
| 1 | SIMPLE | routes | ref | PRIMARY,user_id | user_id | 4 | vnames.users.id | 1 | Using where |
| 1 | SIMPLE | aliases | ref | route_id | route_id | 4 | vnames.routes.id | 1 | Using where with pushed condition |
+----+-------------+---------+------+-----------------+----------+---------+------------------+--------+-----------------------------------+
また、3つのテーブルのShowIndexesの出力は次のとおりです。
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| aliases | 0 | PRIMARY | 1 | id | A | 377197 | NULL | NULL | | BTREE | |
| aliases | 1 | route_id | 1 | route_id | A | 377197 | NULL | NULL | | BTREE | |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| routes | 0 | PRIMARY | 1 | id | A | 208442 | NULL | NULL | | BTREE | |
| routes | 1 | user_id | 1 | user_id | A | 208442 | NULL | NULL | | BTREE | |
| routes | 1 | address | 1 | address | A | 208442 | NULL | NULL | | BTREE | |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| users | 0 | PRIMARY | 1 | id | A | 177803 | NULL | NULL | | BTREE | |
| users | 1 | userid | 1 | userid | A | 177803 | NULL | NULL | | BTREE | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
どんな助け/提案も大歓迎です。
テーブルのボリュームが原因で、このクエリが停止したと思われます。すべてのユーザーIDを24000回返すクエリを実行すると、最終的にパフォーマンスの問題が発生します。
ある時点で、テーブルがメモリに収まらないところまで成長し(非常に高速なアクセス)、ディスクからデータを読み取ることになります(ほとんどのクエリで非常に遅いクエリ。これは突然の切り替えです。私が書いたクエリの1つはこれが発生したときは1秒未満から5分です。テーブルを圧縮できる場合は、しばらくの間状態が解決する可能性があります。メモリを追加すると役立つ場合があります(データベースに十分なバッファスペースがない場合でも、O/Sはデータをバッファリングします。)
これは私がそれを理解するためにクエリをフォーマットした方法です。
SELECT userid
FROM users
LEFT OUTER JOIN routes
ON routes.user_id = users.id
LEFT OUTER JOIN aliases
ON aliases.route_id = routes.id
WHERE aliases.name = 'xxxx'
AND domain_id = 8;
Aliases.nameに一致するエイリアスを検索する場合は、その列にインデックスを付けると役立ちます。
LEFT OUTER JOINSに基づいて、すべてのユーザーまたはdomain_id = 8のすべてのユーザーのユーザーIDを取得する必要があります。このクエリを読んでいると、次のように書くのに時間がかかります。
SELECT userid
FROM users;
または
SELECT userid
from users
WHERE domain_id = 8;
ただし、エイリアスとドメインが一致する場合は、ユーザーIDが必要になると思います。
SELECT userid
FROM users
JOIN routes
ON routes.user_id = users.id
JOIN aliases
ON aliases.route_id = routes.id
WHERE aliases.name = 'xxxx'
AND domain_id = 8;
Aliases.nameの値に一致するユーザーIDを探している場合は、aliases.nameのインデックスを作成すると便利です。