MySQLで同じSELECT文の2回目以降の読み取り速度を向上させるクエリキャッシュですが、MySQL 8.0ではキャッシュしません!ということについて書いていきます。
MySQL5.7までは、デフォルトでONになっていたクエリキャッシュですが、MySQL8.0では使えない機能(削除された機能)となります。
MySQL5.7→8.0に移行時は要注意ですね。
The query cache is deprecated as of MySQL 5.7.20, and is removed in MySQL 8.0.
MySQL :: MySQL 5.7 Reference Manual :: 8.10.3 The MySQL Query Cache
MySQL5.7まではデフォルトON
→これにより、同じSELECT文の2回目以降の読み取り速度が向上していた
MySQL8.0では使えない
まずは、具体的にクエリキャッシュの挙動について書いていきます!
クエリキャッシュの挙動
クエリキャッシュの挙動は以下のようになります。
- SELECT文の結果をメモリに保存する
- 同じSELECT文を発行すると、2回目以降はメモリ上の保存データ(キャシュデータ)が返される
- UPDATEするとメモリ上の保存データ(キャッシュデータ)はクリアされる
- これにより、UPDATE前の古いデータが、SELECTの結果として返却されることはない
次は、クエリキャッシュON(MySQL5.7)とクエリキャッシュOFF(MySQL8.0)で実際の挙動を確認していきます。
クエリキャッシュの動作検証
環境:AWS Aurora
インスタンス:db.t3.medium
クエリキャッシュON(MySQL5.7)とクエリキャッシュOFF(MySQL8.0)で、それぞれ以下の挙動を確認します。
同じSELECT文を3回実行した際の速度検証
UPDATEでデータ更新後に、再度、同じSELECT文を3回実行した際の速度検証
準備
以下の2つを準備します。
テーブル作成
テストデータ作成用のプロシージャ作成
テーブル作成
以下のテーブルを用意します。インデックスなしテーブルです。
create table user(
id INT,
type INT,
name VARCHAR(255)
);
テストデータ作成用のプロシージャ作成
テストデータはプロシージャーで作成します。
以下の通りデータ作成してくれるようになっています。
- user.id:カウントアップ形式で数値を格納
- user.type:カウントを2で割った余りを格納(あまり意味がないカラムです。)
- user.name:「user_name_{カウント}」の値を格納
-- 区切り文字を「//」に変更する
DELIMITER //
-- make_sample_dataというテストデータ作成用プロシージャーを作成する
create procedure make_sample_data(in i int)
begin
declare count int default 0;
-- 繰り返し
while count < i do
set count = count + 1;
INSERT INTO user VALUES(count, MOD(count,2),CONCAT('usr_name_',count));
end while;
end
//
-- 区切り文字を「;」に戻す
DELIMITER ;
それでは、クエリキャッシュON(MySQL5.7)の挙動から確認していきます。
クエリキャッシュON(MySQL5.7)の挙動
◾️クエリキャッシュがONであることの確認
mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| have_query_cache | YES |
+------------------+-------+
1 row in set (0.01 sec)
◾️100万件インサート
mysql> call make_sample_data(1000000);
Query OK, 1 row affected (48.14 sec)
◾️1件SELECTを3回やってみる
<結果>
1回目:0.47 sec→2回目:0.02 sec→3回目:0.01 sec
2回目以降はキャッシュにより、大幅に速度向上していることが分かる
mysql> select * from user where id = 1;
+------+------+------------+
| id | type | name |
+------+------+------------+
| 1 | 1 | usr_name_1 |
+------+------+------------+
1 row in set (0.47 sec)
mysql> select * from user where id = 1;
+------+------+------------+
| id | type | name |
+------+------+------------+
| 1 | 1 | usr_name_1 |
+------+------+------------+
1 row in set (0.02 sec)
mysql> select * from user where id = 1;
+------+------+------------+
| id | type | name |
+------+------+------------+
| 1 | 1 | usr_name_1 |
+------+------+------------+
1 row in set (0.01 sec)
◾️SELECT対象データをUPDATEする
mysql> update user set name = 'update_name' where id = 1;
Query OK, 0 rows affected (0.72 sec)
Rows matched: 1 Changed: 0 Warnings: 0
◾️UPDATE後に再度、1件SELECTを3回やってみる
<結果>
1回目:0.45 sec→2回目:0.00 sec→3回目:0.00 sec
UPDATEによりキャッシュがクリアされ、1回目は遅くなり、2回目以降はキャッシュにより、大幅に速度向上していることが分かる
mysql> select * from user where id = 1;
+------+------+-------------+
| id | type | name |
+------+------+-------------+
| 1 | 1 | update_name |
+------+------+-------------+
1 row in set (0.45 sec)
mysql> select * from user where id = 1;
+------+------+-------------+
| id | type | name |
+------+------+-------------+
| 1 | 1 | update_name |
+------+------+-------------+
1 row in set (0.00 sec)
mysql> select * from user where id = 1;
+------+------+-------------+
| id | type | name |
+------+------+-------------+
| 1 | 1 | update_name |
+------+------+-------------+
1 row in set (0.00 sec)
次に、クエリキャッシュOFF(MySQL8.0)の挙動を確認していきます。
クエリキャッシュOFF(MySQL8.0)の挙動
◾️クエリキャッシュがOFFであることの確認
mysql> SHOW VARIABLES LIKE 'have_query_cache';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| have_query_cache | NO |
+------------------+-------+
1 row in set (0.00 sec)
◾️100万件インサート
mysql> call make_sample_data(1000000);
Query OK, 1 row affected (47.50 sec)
◾️1件SELECTを3回やってみる
<結果>
1回目:0.57 sec→2回目:0.55 sec→3回目:0.58 sec
2回目以降も速度はほとんど変わらず、キャッシュが効いていないことが分かる。
mysql> select * from user where id = 1;
+------+------+------------+
| id | type | name |
+------+------+------------+
| 1 | 1 | usr_name_1 |
+------+------+------------+
1 row in set (0.57 sec)
mysql> select * from user where id = 1;
+------+------+------------+
| id | type | name |
+------+------+------------+
| 1 | 1 | usr_name_1 |
+------+------+------------+
1 row in set (0.55 sec)
mysql> select * from user where id = 1;
+------+------+------------+
| id | type | name |
+------+------+------------+
| 1 | 1 | usr_name_1 |
+------+------+------------+
1 row in set (0.58 sec)
◾️SELECT対象データをUPDATEする
mysql> update user set name = 'update_name' where id = 1;
Query OK, 1 row affected (0.90 sec)
Rows matched: 1 Changed: 1 Warnings: 0
◾️UPDATE後に再度、1件SELECTを3回やってみる
<結果>
1回目:0.55 sec→2回目:0.54 sec→3回目:0.54 sec
UPDATE後も変わらず、キャッシュが効かないため、速度が変わらないことが分かる
mysql> select * from user where id = 1;
+------+------+-------------+
| id | type | name |
+------+------+-------------+
| 1 | 1 | update_name |
+------+------+-------------+
1 row in set (0.55 sec)
mysql> select * from user where id = 1;
+------+------+-------------+
| id | type | name |
+------+------+-------------+
| 1 | 1 | update_name |
+------+------+-------------+
1 row in set (0.54 sec)
mysql> select * from user where id = 1;
+------+------+-------------+
| id | type | name |
+------+------+-------------+
| 1 | 1 | update_name |
+------+------+-------------+
1 row in set (0.54 sec)
まとめ
クエリキャッシュの挙動について、動作検証しましたー!
以下のことがわかったかと思いまーす!
MySQL5.7まではデフォルトON
→同じSELECT文の2回目以降の読み取りの速度が向上していた
→UPDATE時にキャッシュがクリアされるため、UPDATE後の1回目のSELECTはキャッシュが効かず、2回目以降キャッシュが効く
MySQL8.0では使えない