Ubuntu 18.04でクエリキャッシュを使用してMySQLを最適化する方法

著者は、Write for DOnationsプログラムの一部として寄付を受け取るためにApache Software Foundationを選択しました。

前書き

Query cacheは、データベースからのデータ取得を高速化する顕著なMySQL機能です。 これは、MySQLSELECTステートメントを取得したレコードセットと一緒にメモリに保存することで実現されます。クライアントが同一のクエリを要求した場合、データベースからコマンドを再度実行しなくても、データをより高速に提供できます。

RAMからキャッシュされたデータ(ランダムアクセスメモリ)は、ディスクから読み取られたデータと比較してアクセス時間が短いため、待ち時間が短縮され、入出力(I / O)操作が改善されます。 一例として、WordPressサイトや、読み取り呼び出しが多くデータの変更頻度が低いeコマースポータルの場合、クエリキャッシュを使用すると、データベースサーバーのパフォーマンスが大幅に向上し、スケーラビリティが向上します。

このチュートリアルでは、最初にクエリキャッシュを使用せずにMySQLを構成し、クエリを実行して、実行速度を確認します。 次に、クエリキャッシュを設定し、それを有効にしてMySQLサーバーをテストし、パフォーマンスの違いを示します。

[.note]#Note:クエリキャッシュはMySQL 5.7.20で非推奨になり、MySQL 8.0で削除されましたが、サポートされているバージョンのMySQLを使用している場合は依然として強力なツールです。 ただし、新しいバージョンのMySQLを使用している場合は、ProxySQLなどの代替サードパーティツールを採用して、MySQLデータベースのパフォーマンスを最適化できます。

前提条件

開始する前に、次のものが必要です。

  • ファイアウォールと非rootユーザーで構成された1つのUbuntu 18.04サーバー。 Initial Server Setup with Ubuntu 18.04ガイドを参照して、サーバーを構成できます。

  • このHow To Install MySQL on Ubuntu 18.04チュートリアルで詳しく説明されているようにセットアップされたMySQLサーバー。 MySQLサーバーのルートパスワードを設定していることを確認します。

[[step-1 -—- query-cacheの可用性のチェック]] ==ステップ1—クエリキャッシュの可用性のチェック

クエリキャッシュを設定する前に、MySQLのバージョンがこの機能をサポートしているかどうかを確認します。 まず、Ubuntu 18.04サーバーへのssh

ssh user_name@your_server_ip

次に、次のコマンドを実行して、rootユーザーとしてMySQLサーバーにログインします。

sudo mysql -u root -p

プロンプトが表示されたらMySQLサーバーのrootパスワードを入力し、ENTERを押して続行します。

次のコマンドを使用して、クエリキャッシュがサポートされているかどうかを確認します。

show variables like 'have_query_cache';

次のような出力が表示されます。

Output+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | YES   |
+------------------+-------+
1 row in set (0.01 sec)

have_query_cacheの値がYESに設定されていることがわかります。これは、クエリキャッシュがサポートされていることを意味します。 ご使用のバージョンがクエリキャッシュをサポートしていないことを示す出力を受け取った場合は、詳細について「概要」セクションの注を参照してください。

MySQLのバージョンがクエリキャッシュをサポートしていることを確認し確認したので、データベースサーバーでこの機能を制御する変数の調査に進みます。

[[step-2 -—- checking-the-default-query-cache-variables]] ==ステップ2—デフォルトのクエリキャッシュ変数を確認する

MySQLでは、多くの変数がクエリキャッシュを制御します。 この手順では、MySQLに同梱されているデフォルト値を確認し、各変数が制御するものを理解します。

次のコマンドを使用して、これらの変数を調べることができます。

show variables like 'query_cache_%' ;

出力に変数がリストされます:

Output+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 16777216 |
| query_cache_type             | OFF      |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+
5 rows in set (0.00 sec)

query_cache_limit値は、キャッシュできる個々のクエリ結果の最大サイズを決定します。 デフォルト値は1,048,576バイトで、これは1MBに相当します。

MySQLは、キャッシュされたデータを1つの大きな塊で処理しません。代わりに、ブロックで処理されます。 各ブロックに割り当てられるメモリの最小量は、query_cache_min_res_unit変数によって決定されます。 デフォルト値は4096バイトまたは4KBです。

query_cache_sizeは、クエリキャッシュに割り当てられるメモリの合計量を制御します。 値がゼロに設定されている場合、クエリキャッシュが無効になっていることを意味します。 ほとんどの場合、デフォルト値は16,777,216(約16MB)に設定されます。 また、query_cache_sizeは、その構造を割り当てるために少なくとも40KBを必要とすることに注意してください。 ここで割り当てられる値は、最も近い1024バイトブロックに揃えられます。 これは、報告された値が設定したものとわずかに異なる場合があることを意味します。

MySQLは、query_cache_type変数を調べることにより、キャッシュするクエリを決定します。 この値を0またはOFFに設定すると、キャッシュされたクエリのキャッシュまたは取得が防止されます。 1に設定して、SELECT SQL_NO_CACHEステートメントで始まるクエリを除くすべてのクエリのキャッシュを有効にすることもできます。 2の値は、SELECT SQL_CACHEコマンドで始まるクエリのみをキャッシュするようにMySQLに指示します。

変数query_cache_wlock_invalidateは、クエリで使用されるテーブルがロックされている場合にMySQLがキャッシュから結果を取得するかどうかを制御します。 デフォルト値はOFFです。

[.note]#Note:query_cache_wlock_invalidate変数は、MySQLバージョン5.7.20で非推奨になりました。 その結果、使用しているMySQLのバージョンによっては、これが出力に表示されない場合があります。

MySQLクエリキャッシュを制御するシステム変数を確認したら、最初に機能を有効にせずにMySQLの動作をテストします。

[[step-3 -—- testing-your-mysql-server-without-query-cache]] ==ステップ3—クエリキャッシュなしでMySQLサーバーをテストする

このチュートリアルの目的は、クエリキャッシュ機能を使用してMySQLサーバーを最適化することです。 速度の違いを確認するには、クエリを実行して、機能を実装する前後のパフォーマンスを確認します。

この手順では、サンプルデータベースを作成し、データを挿入して、クエリキャッシュなしでMySQLがどのように動作するかを確認します。

MySQLサーバーにログインしたまま、データベースを作成し、次のコマンドを実行してsample_dbという名前を付けます。

Create database sample_db;
OutputQuery OK, 1 row affected (0.00 sec)

次に、データベースに切り替えます。

Use sample_db;
OutputDatabase changed

2つのフィールド(customer_idcustomer_name)を持つテーブルを作成し、customersという名前を付けます。

Create table customers (customer_id INT PRIMARY KEY, customer_name VARCHAR(50) NOT NULL) Engine = InnoDB;
OutputQuery OK, 0 rows affected (0.01 sec)

次に、次のコマンドを実行してサンプルデータを挿入します。

Insert into customers(customer_id, customer_name) values ('1', 'JANE DOE');
Insert into customers(customer_id, customer_name) values ('2', 'JANIE DOE');
Insert into customers(customer_id, customer_name) values ('3', 'JOHN ROE');
Insert into customers(customer_id, customer_name) values ('4', 'MARY ROE');
Insert into customers(customer_id, customer_name) values ('5', 'RICHARD ROE');
Insert into customers(customer_id, customer_name) values ('6', 'JOHNNY DOE');
Insert into customers(customer_id, customer_name) values ('7', 'JOHN SMITH');
Insert into customers(customer_id, customer_name) values ('8', 'JOE BLOGGS');
Insert into customers(customer_id, customer_name) values ('9', 'JANE POE');
Insert into customers(customer_id, customer_name) values ('10', 'MARK MOE');
OutputQuery OK, 1 row affected (0.01 sec)
Query OK, 1 row affected (0.00 sec)
...

次のステップは、MySQLクエリのパフォーマンスを監視するための分析サービスであるMySQL profilerを開始することです。 現在のセッションのプロファイルをオンにするには、次のコマンドを実行して、1に設定します。これはオンです。

SET profiling = 1;
OutputQuery OK, 0 rows affected, 1 warning (0.00 sec)

次に、次のクエリを実行して、すべての顧客を取得します。

Select * from customers;

次の出力が表示されます。

Output+-------------+---------------+
| customer_id | customer_name |
+-------------+---------------+
|           1 | JANE DOE      |
|           2 | JANIE DOE     |
|           3 | JOHN ROE      |
|           4 | MARY ROE      |
|           5 | RICHARD ROE   |
|           6 | JOHNNY DOE    |
|           7 | JOHN SMITH    |
|           8 | JOE BLOGGS    |
|           9 | JANE POE      |
|          10 | MARK MOE      |
+-------------+---------------+
10 rows in set (0.00 sec)

次に、SHOW PROFILESコマンドを実行して、実行したばかりのSELECTクエリに関するパフォーマンス情報を取得します。

SHOW PROFILES;

次のような出力が得られます。

Output+----------+------------+-------------------------+
| Query_ID | Duration   | Query                   |
+----------+------------+-------------------------+
|        1 | 0.00044075 | Select * from customers |
+----------+------------+-------------------------+
1 row in set, 1 warning (0.00 sec)

出力には、データベースからレコードを取得するときにMySQLが費やした合計時間が表示されます。 クエリキャッシュが有効になっている場合は、次の手順でこのデータを比較するので、Durationをメモしておいてください。 これは、SHOW PROFILESコマンドが将来のMySQLリリースで削除され、Performance Schemaに置き換えられることを示しているだけなので、出力内の警告は無視してかまいません。

次に、MySQLコマンドラインインターフェイスを終了します。

quit;

クエリキャッシュを有効にする前にMySQLでクエリを実行し、Durationまたはレコードの取得に費やした時間を書き留めました。 次に、クエリキャッシュを有効にして、同じクエリを実行したときにパフォーマンスが向上するかどうかを確認します。

[[step-4 -—- setting-up-query-cache]] ==ステップ4—クエリキャッシュの設定

前の手順では、クエリキャッシュを有効にする前に、サンプルデータを作成し、SELECTステートメントを実行しました。 この手順では、MySQL構成ファイルを編集してクエリキャッシュを有効にします。

nanoを使用してファイルを編集します。

sudo nano /etc/mysql/my.cnf

ファイルの最後に次の情報を追加します。

/etc/mysql/my.cnf

...
[mysqld]
query_cache_type=1
query_cache_size = 10M
query_cache_limit=256K

ここでは、query_cache_type1に設定して、クエリキャッシュを有効にしました。 また、個々のクエリ制限サイズを256Kに設定し、query_cache_sizeの値を10Mに設定して、クエリキャッシュに10メガバイトを割り当てるようにMySQLに指示しました。

CTRL +XYENTERの順に押して、ファイルを保存して閉じます。 次に、MySQLサーバーを再起動して、変更を実装します。

sudo systemctl restart mysql

これでクエリキャッシュが有効になりました。

クエリキャッシュを構成し、MySQLを再起動して変更を適用したら、機能を有効にしてMySQLのパフォーマンスをテストします。

[[step-5 -—- testing-your-mysql-server-with-query-cache-enabled]] ==ステップ5—クエリキャッシュを有効にしてMySQLサーバーをテストする

この手順では、手順3で実行した同じクエリをもう一度実行して、クエリキャッシュがMySQLサーバーのパフォーマンスを最適化する方法を確認します。

まず、rootユーザーとしてMySQLサーバーに接続します。

sudo mysql -u root -p

データベースサーバーのrootパスワードを入力し、ENTERを押して続行します。

前の手順で設定したセットを確認して、クエリキャッシュが有効になっていることを確認します。

show variables like 'query_cache_%' ;

次の出力が表示されます。

Output+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 262144   |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 10485760 |
| query_cache_type             | ON       |
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+
5 rows in set (0.01 sec)

変数query_cache_typeONに設定されます。これにより、前の手順で定義したパラメータを使用してクエリキャッシュが有効になったことを確認できます。

以前に作成したsample_dbデータベースに切り替えます。

Use sample_db;

MySQLプロファイラーを起動します。

SET profiling = 1;

次に、十分なプロファイリング情報を生成するために、クエリを実行してすべての顧客を少なくとも2回取得します。

最初のクエリを実行すると、MySQLが結果のキャッシュを作成するため、キャッシュをトリガーするにはクエリを2回実行する必要があります。

Select * from customers;
Select * from customers;

次に、プロファイル情報をリストします。

SHOW PROFILES;

次のような出力が表示されます。

Output+----------+------------+-------------------------+
| Query_ID | Duration   | Query                   |
+----------+------------+-------------------------+
|        1 | 0.00049250 | Select * from customers |
|        2 | 0.00026000 | Select * from customers |
+----------+------------+-------------------------+
2 rows in set, 1 warning (0.00 sec)

ご覧のとおり、クエリの実行にかかる時間は、このステップで0.00044075(ステップ3のクエリキャッシュなし)から0.00026000(2番目のクエリ)に大幅に短縮されました。

最初のクエリを詳細にプロファイリングすることで、クエリキャッシュ機能を有効にすることで最適化を確認できます。

SHOW PROFILE FOR QUERY 1;
Output+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.000025 |
| Waiting for query cache lock   | 0.000004 |
| starting                       | 0.000003 |
| checking query cache for query | 0.000045 |
| checking permissions           | 0.000008 |
| Opening tables                 | 0.000014 |
| init                           | 0.000018 |
| System lock                    | 0.000008 |
| Waiting for query cache lock   | 0.000002 |
| System lock                    | 0.000018 |
| optimizing                     | 0.000003 |
| statistics                     | 0.000013 |
| preparing                      | 0.000010 |
| executing                      | 0.000003 |
| Sending data                   | 0.000048 |
| end                            | 0.000004 |
| query end                      | 0.000006 |
| closing tables                 | 0.000006 |
| freeing items                  | 0.000006 |
| Waiting for query cache lock   | 0.000003 |
| freeing items                  | 0.000213 |
| Waiting for query cache lock   | 0.000019 |
| freeing items                  | 0.000002 |
| storing result in query cache  | 0.000003 |
| cleaning up                    | 0.000012 |
+--------------------------------+----------+
25 rows in set, 1 warning (0.00 sec)

次のコマンドを実行して、キャッシュされている2番目のクエリのプロファイル情報を表示します。

SHOW PROFILE FOR QUERY 2;
Output+--------------------------------+----------+
| Status                         | Duration |
+--------------------------------+----------+
| starting                       | 0.000024 |
| Waiting for query cache lock   | 0.000003 |
| starting                       | 0.000002 |
| checking query cache for query | 0.000006 |
| checking privileges on cached  | 0.000003 |
| checking permissions           | 0.000027 |
| sending cached result to clien | 0.000187 |
| cleaning up                    | 0.000008 |
+--------------------------------+----------+
8 rows in set, 1 warning (0.00 sec)

プロファイラからの出力は、MySQLがディスクからデータを読み取る代わりにクエリキャッシュからデータを取得できたため、2番目のクエリの時間が短縮されたことを示しています。 各クエリの2セットの出力を比較できます。 QUERY 2のプロファイル情報を見ると、sending cached result to clientのステータスは、Opening tablesステータスがないため、データがキャッシュから読み取られ、テーブルが開かれていないことを示しています。

サーバーでMySQLクエリキャッシュ機能を有効にすると、読み取り速度が向上します。

結論

Ubuntu 18.04でMySQLサーバーを高速化するためにクエリキャッシュを設定しました。 MySQLのクエリキャッシュなどの機能を使用すると、WebサイトまたはWebアプリケーションの速度を向上させることができます。 キャッシングは、SQLステートメントの不必要な実行を削減し、データベースを最適化するための強く推奨される一般的な方法です。 MySQLサーバーの高速化の詳細については、How To Set Up a Remote Database to Optimize Site Performance with MySQL on Ubuntu 18.04チュートリアルを試してください。