ただメモができるだけのブラウザアプリ「TextArea」はこちらw

MySQLで2回目のSELECTで速度が向上するクエリキャッシュについて

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つを準備します。

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では使えない

スポンサーリンク
MySQL
フォローする
さゆフィクション