MySQLデータベースのワークロードは、処理するクエリの数によって決まります。 MySQLの速度低下が発生する可能性のある状況がいくつかあります。最初の可能性は、適切なインデックスを使用していないクエリがあるかどうかです。クエリがインデックスを利用できない場合、MySQLサーバーはそのクエリを処理するためにより多くのリソースと時間を使用する必要があります。クエリを監視することで、速度低下の根本原因であるSQLコードを特定し、全体的なパフォーマンスが低下する前に修正することができます。
このブログ投稿では、ClusterControlで使用可能なクエリ外れ値機能に焦点を当て、データベースのパフォーマンスの向上にどのように役立つかを確認します。一般に、ClusterControlはMySQLクエリのサンプリングを次の2つの方法で実行します。
- パフォーマンススキーマからクエリを取得します(推奨 。
- MySQLSlowQueryのコンテンツを解析します。
パフォーマンススキーマが無効になっている場合、ClusterControlはデフォルトでSlowQueryログになります。 ClusterControlがこれを実行する方法の詳細については、このブログ投稿「MySQL、MariaDB、およびPerconaサーバー用のClusterControlクエリモニターの使用方法」を確認してください。
外れ値は、そのタイプの通常のクエリ時間よりも長い時間がかかるクエリです。これを文字通り「不適切に記述された」クエリと見なさないでください。これは、改善される可能性のある潜在的な次善の一般的なクエリとして扱う必要があります。いくつかのサンプルの後、ClusterControlに十分な統計がある場合、レイテンシが通常よりも高いかどうか(2シグマ+ average_query_time)を判断でき、それは外れ値であり、クエリ外れ値に追加されます。
この機能は、トップクエリ機能に依存しています。クエリ監視が有効で、上位クエリがキャプチャされて入力されている場合、クエリ外れ値はこれらを要約し、タイムスタンプに基づくフィルターを提供します。注意が必要なクエリのリストを表示するには、ClusterControl-> Query Monitor-> Query Outliersに移動し、いくつかのクエリがリストされていることを確認します(存在する場合):
上のスクリーンショットからわかるように、外れ値は基本的に次のようなクエリです。平均クエリ時間の少なくとも2倍の時間がかかりました。最初の最初のエントリでは、平均時間は34.41ミリ秒ですが、外れ値のクエリ時間は140ミリ秒です(平均時間の2倍以上)。同様に、次のエントリでは、[クエリ時間]列と[平均クエリ時間]列は、特定の外れ値クエリの未処理を正当化するための2つの重要なものです。
次のスクリーンショットで強調表示されているように、1週間前など、より長い期間を調べることで、特定のクエリの異常値のパターンを見つけるのは比較的簡単です。
各行をクリックすると、実際のクエリ全体を確認できます。次のセクションに示すように、問題を特定して理解するのに役立ちます。
外れ値を修正するには、クエリの性質、テーブルのストレージエンジン、データベースバージョン、クラスタリングタイプ、およびクエリの影響を理解する必要があります。場合によっては、外れ値クエリがデータベース全体のパフォーマンスを実際に低下させていないことがあります。この例のように、クエリは1週間ずっと目立ち、キャプチャされたクエリタイプはこれだけだったので、可能であればこのクエリを修正または改善することをお勧めします。
この場合と同様に、外れ値のクエリは次のとおりです。
SELECT i2l.country_code AS country_code, i2l.country_name AS country_name
FROM ip2location i2l
WHERE (i2l.ip_to >= INET_ATON('104.144.171.139')
AND i2l.ip_from <= INET_ATON('104.144.171.139'))
LIMIT 1
OFFSET 0;
+--------------+---------------+
| country_code | country_name |
+--------------+---------------+
| US | United States |
+--------------+---------------+
EXPLAINの使用
このクエリは、テーブルip2location上のIPアドレスに対するユーザーの地理的位置情報(国コードと国名)を決定するための読み取り専用の範囲選択クエリです。 EXPLAINステートメントを使用すると、クエリ実行プランを理解するのに役立ちます。
mysql> EXPLAIN SELECT i2l.country_code AS country_code, i2l.country_name AS country_name
FROM ip2location i2l
WHERE (i2l.ip_to>=INET_ATON('104.144.171.139')
AND i2l.ip_from<=INET_ATON('104.144.171.139'))
LIMIT 1 OFFSET 0;
+----+-------------+-------+------------+-------+--------------------------------------+-------------+---------+------+-------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+--------------------------------------+-------------+---------+------+-------+----------+------------------------------------+
| 1 | SIMPLE | i2l | NULL | range | idx_ip_from,idx_ip_to,idx_ip_from_to | idx_ip_from | 5 | NULL | 66043 | 50.00 | Using index condition; Using where |
+----+-------------+-------+------------+-------+--------------------------------------+-------------+---------+------+-------+----------+------------------------------------+
クエリは、50%の潜在的な行(フィルター処理済み)を持つインデックスidx_ip_fromを使用して、テーブルの範囲スキャンで実行されます。
ip2locationのテーブル構造を見てください:
mysql> SHOW CREATE TABLE ip2location\G
*************************** 1. row ***************************
Table: ip2location
Create Table: CREATE TABLE `ip2location` (
`ip_from` int(10) unsigned DEFAULT NULL,
`ip_to` int(10) unsigned DEFAULT NULL,
`country_code` char(2) COLLATE utf8_bin DEFAULT NULL,
`country_name` varchar(64) COLLATE utf8_bin DEFAULT NULL,
KEY `idx_ip_from` (`ip_from`),
KEY `idx_ip_to` (`ip_to`),
KEY `idx_ip_from_to` (`ip_from`,`ip_to`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
このテーブルはIP2locationデータベースに基づいており、更新/書き込みされることはめったになく、通常は暦月の初日にのみ行われます(ベンダーが推奨)。したがって、1つのオプションは、テーブルを固定行形式のMyISAM(MySQL)またはAria(MariaDB)ストレージエンジンに変換して、読み取り専用のパフォーマンスを向上させることです。これは、MySQLまたはMariaDBスタンドアロンまたはレプリケーションで実行している場合にのみ適用されることに注意してください。 Galeraクラスターとグループレプリケーションでは、InnoDBストレージエンジンに固執してください(何をしているのかわからない場合)。
とにかく、テーブルをInnoDBから固定行形式のMyISAMに変換するには、次のコマンドを実行するだけです。
ALTER TABLE ip2location ENGINE=MyISAM ROW_FORMAT=FIXED;
1000回のランダムIPアドレスルックアップテストを使用した測定では、MyISAMと固定行形式を使用するとクエリのパフォーマンスが約20%向上しました。
- 平均時間(InnoDB):21.467823ミリ秒
- 平均時間(MyISAM修正済み):17.175942ミリ秒
- 改善: 19.992157565301%
この結果は、テーブルが変更された直後に期待できます。上位層(アプリケーション/ロードバランサー)を変更する必要はありません。
もう1つの方法は、クエリプランを検査し、より効率的なアプローチを使用して、より良いクエリ実行プランを作成することです。同じクエリは、以下のようにサブクエリを使用して作成することもできます。
SELECT `country_code`, `country_name` FROM
(SELECT `country_code`, `country_name`, `ip_from`
FROM `ip2location`
WHERE ip_to >= INET_ATON('104.144.171.139')
LIMIT 1)
AS temptable
WHERE ip_from <= INET_ATON('104.144.171.139');
調整されたクエリには、次のクエリ実行プランがあります。
mysql> EXPLAIN SELECT `country_code`,`country_name` FROM
(SELECT `country_code`, `country_name`, `ip_from`
FROM `ip2location`
WHERE ip_to >= INET_ATON('104.144.171.139')
LIMIT 1)
AS temptable
WHERE ip_from <= INET_ATON('104.144.171.139');
+----+-------------+--------------+------------+--------+---------------+-----------+---------+------+-------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------+------------+--------+---------------+-----------+---------+------+-------+----------+-----------------------+
| 1 | PRIMARY | <derived2> | NULL | system | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
| 2 | DERIVED | ip2location | NULL | range | idx_ip_to | idx_ip_to | 5 | NULL | 66380 | 100.00 | Using index condition |
+----+-------------+--------------+------------+--------+---------------+-----------+---------+------+-------+----------+-----------------------+
サブクエリを使用すると、1つのインデックスに焦点を当てた派生テーブルを使用してクエリを最適化できます。クエリは、ip_to値がIPアドレス値以上である1つのレコードのみを返す必要があります。これにより、潜在的な行(フィルター処理された)が100%に達することができ、これが最も効率的です。次に、ip_fromがIPアドレス値以下であることを確認します。もしそうなら、私たちはレコードを見つける必要があります。それ以外の場合、IPアドレスはip2locationテーブルに存在しません。
私たちの測定では、サブクエリを使用してクエリのパフォーマンスが約99%向上しました:
- 平均時間(InnoDB +範囲スキャン):22.87112ミリ秒
- 平均時間(InnoDB +サブクエリ):0.14744ミリ秒
- 改善: 99.355344207017%
上記の最適化により、このタイプのクエリのサブミリ秒のクエリ実行時間がわかります。これは、以前の平均時間が22ミリ秒であることを考えると大幅な改善です。ただし、この調整されたクエリを利用するには、上位層(アプリケーション/ロードバランサー)にいくつかの変更を加える必要があります。
調整されたクエリを使用するようにアプリケーションにパッチを適用するか、データベースサーバーに到達する前に外れ値クエリを書き直します。これは、ProxySQL(クエリルール)やMariaDB MaxScale(ステートメント書き換えフィルター)などのMySQLロードバランサーを使用するか、MySQLクエリ書き換えプラグインを使用することで実現できます。次の例では、データベースクラスターの前でProxySQLを使用し、ルールを作成して、低速のクエリを高速のクエリに書き換えることができます。例:
クエリルールを保存し、ClusterControlの[クエリ外れ値]ページを監視します。この修正により、クエリルールがアクティブ化された後、リストから外れ値のクエリが明らかに削除されます。
クエリの外れ値は、パフォーマンスの問題が制御不能になる前に理解して修正するのに役立つプロアクティブなクエリ監視ツールです。アプリケーションが成長し、要求が厳しくなるにつれて、このツールは、途中で適切なデータベースパフォーマンスを維持するのに役立ちます。