41から始めました

文字通り41歳から始めたブログです。DB(MySQL)を使ってお仕事してるので、DB周りの話を中心に最近始めたこととかをTwitterのノリで書いています。なお、本サイトにおいて示されている見解は私個人の見解であり、所属団体や組織を代表するものではありません。

【小学校受験】小学校受験を終えて

振り返り

はじめに

先日、娘の小学校受験が終わりました。

多くの人に助けられ、第2志望のところが受かったんで、来年はそこに通うことになります。

(第1志望の学校には行けませんでしたが、それもまた縁かな、と)

色々な人から話を聞くとその学校も調べた以上に評判が良く、親としても段々楽しみになってきました。

娘を通じて初めて経験した小学校受験について、何回かに分けて振り返ってみたいと思います。

受験開始

始めたのは今年の2月でした。(一般的には凄く遅い)

妻にずっと「小学校受験をやりたい」言われ続けていたので、折れた形で認めたのが始まりです。

塾に通わせたものの小学校受験というものがイマイチ良くわかっていませんでした。

国立小を目指す感じで塾に行かせてましたが、コロナで教室に入れず、勉強の様子が見られないまま3か月が過ぎました。

勉強時間

この頃の勉強は塾でやったプリントを復習したり、宿題をやったりしつつ、妻が買い集めた問題集を少しやる程度でした。

大体1日1h勉強したらいい方だったと思います。

3か月後、塾を変更

5月に入り、ようやく塾の方でリモートで勉強の様子を見られるようになり、愕然としました。

できる子には手厚く教え、できない子は別の部屋で素人のような新人先生に教わるスタイルでした。

そして我が子はその新人先生の部屋に…。

新人先生が手厚く教えるならいいんですが、人手も足りず、子供がわかってないところは「親御さんよろしく!」な授業。

わかってなかったら置いていく授業スタイル。

娘もかなりわかってない雰囲気を出していて、娘どうです?と塾の先生に聞いたところ、

今更「ええ、お子さんこのままじゃマズいです」と言う…。

「これはマズい!」といつもは意見が正反対のうちら夫婦が珍しく意見が一致。

3か月も通わせて、何も成長していないことを連絡してこなかった、いや見てなかった(?)塾に対して不信感を持った我が家は早速、近くに今からでも入れる塾が無いか探し始めました。

今度は丁寧に教えてくれて、親がちゃんと授業内容も見れるような塾に。

しかし、既に5月。入塾するとしても6月になる状況で、勉強が遅れているような子を喜んで入れてくれるところはなかなかありません。

そんな時、妻が思い出したのがあるカリスマ先生の塾でした。

そこが家の近くに分校を最近建てたのを知り、連絡してみたところ、土曜日に授業があることから体験に行くことに。

授業はカリスマ先生の息子さんがされていましたが、非常に教え方も丁寧で、できない我が子や他の子にも分かるように教え、それでいて値段も手ごろ。

ここに転塾しよう!と速攻切り替えました。

志望校を国立から私立へ変更

転塾したことは志望校の見直しにもつながりました。

前の塾では国立対策コースにいたので、私立は全く考えていませんでした。

しかし、転塾したことでそもそもどこに行かせるのかを先生と話しながら考え直すようになりました。

ある日、吉祥寺の本校である女子校の教頭先生が話に来るので、その説明会に参加しては?という話を先生から聞き、参加してみることに。

そこで聞いた話が楽しく、ああ、この学校、面白そうやな!俺が入りたい!と思ったのが決め手でした。

色々その学校について調べ、子供に学校の映像を見せたり話したりすると、子供もそこに行きたいと。

そこからは私立でも子供に合いそうだとか、中学や高校もあってしばらく受験はしなくてよくて、カリキュラム的にお金をかける価値がありそうなところを探しました。

その結果、コネに頼れない我が家は頑張って実力を身につけないと入れない私立を目指すことになりました。

勉強時間

子供の気持ちに少し火が付いたことで勉強時間は1日1.5h~2hくらいになりました。

夏から秋にかけて

遅れを取り戻すべく、朝保育園に行く前に朝勉、夕方保育園から帰ってご飯前に少し夕勉、ご飯食べた後夜勉、寝る前絵本タイムというのが毎日行われるようになりました。

まあ、受験やってるところはどのご家庭もやってるんでしょうけど、ここで保育園と専業主婦のママ+幼稚園との差が見えてきます。

圧倒的な時間の差が塾でハッキリ出てきますw(幼稚園だけどやってないご家族は置いときますw)

足りないスキルも見えてきたので、受けるクラスを増やしました。

吉祥寺の本校でしかやってない授業とか自分たちの都合もあって、吉祥寺まで週2回くらい行くようになりました。

これで交通費と親子の体力が毎日削られ続けていました。

夫婦間の衝突も多かったこの頃。

子供に「なんでできないの!他の子はできるのに!」という妻に対し、俺がいい加減にしろというのが日常茶飯事に。

あんまり子供の前で言い争う親の姿なんか見せたくないんですが…。

勉強時間

この頃は1日1.5h~2.5hくらいでした。ただ、保育園に行きながらはこれ以上はどうしても捻出できませんでした。

塾行く行き帰りの電車の中などもこまめに使いましたが、やりすぎるとすぐ風邪をひいてしまいました。

そのため、第一志望校受験前の1か月は保育園を休み、妻も仕事を休んで1日4h+運動1hのような生活をしました。

模試

いくつか夏から秋にかけて模試があって、慣れさせるために受けさせましたが、第一志望どころか第三や第四志望のところすら合格圏内に届かない、常に最下位レベル。

これに妻が毎回激怒。

子供はいつもツラいと小さな声で俺に呟いている感じで、こんなの何故やり続けるのかと疑問になる毎日。

ただ、第一志望の学校は子供も行きたいと自分で思った学校なので、励ましながら、なんとか親子で間違った問題を復習したりし続けました。

そして、10月の末くらいにようやく第一志望の学校に手が届くか届かないかくらいの感じになり、ギリギリ間に合ったようにも見えました…。

本番

小学校受験都道府県により開始のシーズンが違い、

  1. 埼玉は8月から9月、
  2. 神奈川は9月から10月、
  3. 東京は10月後半から11月、
  4. 国立が最後に11月中旬から12月

というスケジュールになっています。

我が家は埼玉1、神奈川2、東京2、国立はとりあえず申し込み可能な4つ受けてみることにしました。

埼玉の学校を受けに行ったときは何の準備もできておらず、ほぼ模試として受けに行っていました。

忘れ物もしてしまい、面接もボロボロであっさり落ちました。

神奈川の学校の一つは妻の行かせたい学校(俺は否定的)だったのですが、ここでも娘が面接でやらかしてしまい、帰りの電車で妻は大激怒。

たった5~6歳の子に失敗するなというほうが無茶だとは思うのですが、小学校受験とは「躾」を見る場でもあるので、そういうやらかしは即アウトになります。

神奈川のもう一つの学校は夫婦ともに「ここはいいね」と思った学校です。

家から遠いことを除けば、自然もあり(学校のすぐそばの林の中にリス!)、中・高、下手すりゃ大学まで受験無しというなかなかの好条件のところ。

ここが受かって、両親ビックリ!

とりあえず最低限の目標はクリアした気になりました。

東京の2のうち、一つは近いので全く興味も無いけど、第一志望前に試験慣れしとこうと思って受けて、案の定面接から玉砕。

そして、第一志望を受けましたが、事件発生。。。そして学校で泣いてしまい、案の定不合格。

ここでテンション駄々下がりなので、後の国立についてはとりあえず。。。な感じで申し込んで、4分の2受けて、全落ちしました。

終わっての感想

最後の12月の試験を受けた直後から複数の嘔吐+39度の熱を出しました。

本人もプレッシャーがあったのか、それとも誰かにうつされたのかわかりませんが、約10か月の受験期間が終わりました。

1勝8敗

受験にかけたお金は150万くらいだと思います。(これは入る学校に支払う分は含みません)

会社の同僚にも時間の面で色々と協力してもらいました。

妻は一か月会社を休職して、給料は丸一か月分0になりました。

数字だけ見るとコスパ悪いようにも見えます。

でも、入れる学校は1つだし、受かった学校が穏やかそう&将来性ありそうなところなので◎とはいかないまでも〇くらいは出資者の親としては思うようにしてますw

また、本人も塾や試験対策で色々な経験を積んだことで、1年前から比べると大きく成長しました。

娘にガンバレガンバレと言い続けたことで、自分もここから更に頑張ろうと言う気持ちになりました。

もう一回やる機会があればもう少しうまくやれるけど、やりたいかと言われると…(苦笑)


次回はこれから小学校受験を受けようかな、どうしようかなと考えている人向けに書いてみます。

MySQL8.0を再起動するとアプリからつながらなくなる理由

この記事は MySQL Advent Calendar 2021 の18日目の記事です。

それ、多分 caching_sha2_password が原因です

この話、実は既にyoku0825さんが語っている話なので、別に目新しさは無いですw

でも、アプリケーションからというように、少しDBへの接続の仕方が変わるとこの話に気づきにくくなってる気がするのであえて書いてみました。

caching_sha2_passwordって何?(おさらい)

caching_sha2_password は MySQL8.0のデフォルトの認証プラグインです。

MySQL5.7まではmysql_native_password がデフォルトの認証プラグインでした。

認証プラグインって?

MySQLサーバは認証方式をプラグイン化しています。

そして、アカウント毎にその認証方式を選べるようにしています。

例えば、

  • ローカルからしか接続しないので、パスワードのみでの認証方式にしたり、
  • 外部からDBへ接続するので暗号化されたパスワードハッシュを使って認証したり、
  • OSユーザーと連携したいので、Windows認証やLDAP認証といった方式も使えます。

caching_sha2_passwordはそれら複数ある認証方式の一つで、SHA-2プラガブル認証をより使いやすくしたものです。

どうやって変更するの?

デフォルトの認証方式はdefault_authentication_pluginを変更すれば

mysql> CREATE USER xxx@localhost;

というように特にIDENTIFIED WITH句を指定しない場合に、そのデフォルトの認証方式が使われます。

逆にIDENTIFIED WITH句を使えば、ユーザーごとに異なる認証方式を設定できます。

ところで、caching_sha2_passwordの何がいいの?

雑ーなマトリクスを作りました。

mysql_native_password sha256_password caching_sha2_password
セキュリティ ×
パフォーマンス ×

caching_sha2_passwordはその名の通り、パスワードのハッシュ化にSHA256を使用していますが、それをサーバーのメモリ上にキャッシュしています。

詳しい話はドキュメント「SHA-2 プラガブル認証のキャッシュ」に書かれています。

さて、本題の原因についての説明です。

くどいようですが、caching_sha2_passwordはMySQL8.0からのデフォルトの認証方式になりました。

そのため、認証方式というものをそもそも意識していないと、「ユーザーが急に入れなくなった!」と感じたりします。

そんなときは以下のようなことを確認してみましょう。

原因と思われる作業

  • MySQLサーバを再起動してませんか?
  • FLUSH PRIVILEGESを実行しませんでしたか?
  • ALTER USERしたユーザーで接続しましたか?
  • CREATE USERしたばかりのユーザーで接続しましたか?
  • MySQLサーバーへ接続する際、非SSLTCP接続じゃないですか?

対応方法

主な方法は以下の通りです。

  1. 接続ユーザーをmysql_native_password認証に変更する
  2. mysqlクライアント等のSSL接続ができるものから一度接続し、認証情報のキャッシュをサーバー上に作った後、非SSL方式で接続する
  3. サーバーの公開鍵を使い、認証を行う
  4. クライアント側、アプリケーションの接続設定部分でSSL接続を有効にする

1の接続ユーザーをmysql_native_password認証に変更するのはセキュリティ的にはあんまりお勧めできません。

2のようにキャッシュが乗った状態なら非SSL方式でもパスワード認証でOKなので、再起動後等に一回つなげばいいんですが、めんどくさいですよね。

というわけで、3か4で対応することをお勧めします。

どうでもいい豆知識ですが、

default_authentication_pluginパラメータでcaching_sha2_passwordを設定できるのはMySQL8.0からです。

設定ファイルに

default_authentication_plugin=caching_sha2_password

と書くと、MySQL5.7以前だとエラーとなり、起動しません。

[ERROR] Can't start server: Invalid value for --default-authentication-plugin

参考情報

MySQL :: MySQL 5.7 Reference Manual :: 6.4.1.4 Caching SHA-2 Pluggable Authentication

MySQL :: MySQL 8.0 Reference Manual :: 6.4.1.2 Caching SHA-2 Pluggable Authentication

MySQL :: MySQL 8.0 リファレンスマニュアル :: 6.4.1.2 SHA-2 プラガブル認証のキャッシュ

明日は

明日は@shallow1729 さんです。お楽しみに!

リモートからBLOB型に画像やPDFファイルを登録する方法

この記事は MySQL Advent Calendar 2021 の5日目の記事です。

久々のブログです。

今年は私事が忙しくてサボりまくってましたが、年明けから頑張ろうかと思いそのためのリハビリです。

今回のネタは備忘録的に自分のために残したかったものです。

BLOB型へのファイルの登録

ローカルなら簡単にできるんだけど

BLOB型に画像やPDFファイルを登録する方法ですが、LOAD_FILE()って関数があって、通常はこれでBLOB型にファイルパスを入れて突っ込みます。

しかし、残念ながらMySQL Serverのあるインスタンス、つまりローカルにそのファイルが無いといけないという制約(*1)があります。

MySQL :: MySQL 8.0 リファレンスマニュアル :: 12.8 文字列関数および演算子

というわけで、リモートからのBLOB型カラムへのバイナリファイルの格納方法がMySQLのコマンドツールでは出来ません。

(マウントすればローカル扱いになるんですが、MySQL Severのローカルとして見える場所にファイルなんか置きたくないよ!って言う声はあるでしょう)

じゃあ、どうすれば?

そんな場合はプリペアドステートメントを使用すれば可能です。

プリペアドステートメント

MySQL :: MySQL 8.0 リファレンスマニュアル :: 13.5 プリペアドステートメント

MySQL C API client library for C プログラム、MySQL Connector/J for Java プログラム、MySQL Connector/NET for .NET を使用するプログラムなどのクライアントプログラミングインタフェースを介して使用できます。

ってわけで、簡易的なコードを書いてみました。

実行例

package java_mysql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.SQLException;
import java.sql.Blob;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;

public class Test {
    public static String URL = "jdbc:mysql://(ホストorIPアドレス):(ポート番号)/(データベース名)";
    public static String USER = "(DBユーザー名)";
    public static String PASSWD = "(DBパスワード)";
    public static String TEST_PDF_PATH = "(ファイルパスとファイル名)";
    public static void main(String[] args) {

        Connection conn;
        Statement st;
        PreparedStatement ps1;
        String sql1 = "INSERT INTO t_blob (b) VALUES(?)";
        byte[] data1;
        
        Blob blob;

        try {
            data1 = Files.readAllBytes(Paths.get(TEST_PDF_PATH));
        } catch(IOException ioex) {
            ioex.printStackTrace();
            return;
        }
        
        try {
            conn = DriverManager.getConnection(URL, USER, PASSWD);
            st = conn.createStatement();
    
            st.execute("CREATE TABLE IF NOT EXISTS t_blob (a SERIAL, b LONGBLOB)");
            st.execute("TRUNCATE t_blob");
            blob = conn.createBlob();
            blob.setBytes(1, data1);
            ps1 = conn.prepareStatement(sql1);
            ps1.setBlob(1, blob);
            ps1.executeUpdate();
            ps1.close();
            st.close();
            conn.close();
        } catch (Exception e) {
            if (e instanceof SQLException) {
            System.out.println("SQLState: " + ((SQLException)e).getSQLState());
            System.out.println("SQLErrorCode: " + ((SQLException)e).getErrorCode());
            System.out.println("SQLErrorMsg: " + ((SQLException)e).getMessage());
            }
            e.printStackTrace();
        }
    }

}

おおまかには以下のような流れです。

  1. Files.readAllBytesで対象の画像ファイルを読み込み、
  2. データベースへ接続
  3. テーブルが存在しない場合は再作成し、存在する場合にはTRUNCATE TABLEをします
  4. プリペアドステートメントを開始し、BLOBファイルを読み込み、DBに挿入します
  5. プリペアドステートメントとDBへの接続を切ります。

ちなみに

プリペアドステートメントじゃなくても、各言語のライブラリなどで格納するものがあったりもするので、その場合はそっちを参照してください。(試してはいない)

npm - mysql でリモートの MySQL サーバーにバイナリファイルのデータを挿入する : まだプログラマーですが何か?

PHP MySQL BLOB: Insert, Update, And Select BLOB Data

さいごに

普段は簡単なコーディングもしないんで、たまにこうやってちょっとしたもの作って、それが動くのを見るだけでも楽しいです。(というか、気軽なコーディングが一番楽しい)

参考資料

Writing and Reading MySQL BLOB Using JDBC

MySQL :: MySQL Connector/NET Developer Guide :: 5.6.3 Reading a BLOB from the Database to a File on Disk

注釈

*1 LOAD_FILE()には、ファイルはサーバーで読取り可能というほかに、そのサイズが max_allowed_packet バイト未満である必要があるという制約もあります。

明日は

明日は@hmatsu47 さんです。お楽しみに!

innodb_strict_mode のセッション値を変更するのに必要な権限(from 8.0.26)

サクッと書けるネタだったので、久々に書きました。

リリースノートを読んでて気になった

MySQL8.0.26のリリースノートのServer Administrationの箇所にこうあった。

Setting the session value of the innodb_strict_mode system variable is now a restricted operation and the session user must have privileges sufficient to set restricted session variables.

For information about the privileges required to set restricted session variables, see System Variable Privileges. (Bug #32944980)

なになに、「システム変数 innodb_strict_mode のセッション値を設定することは、(より)制限された操作に変更され、セッション ユーザーは制限されたセッション変数を設定するのに十分な特権を持っていなければならない。」と。

んで、「制限されたセッション変数を設定するために必要な権限については、「システム変数の権限」を参照してください。」と。

そして、その先のページを読むと、セッションシステム変数を変更するにはMySQL 8.0.14以降 では、必要な権限は SESSION_VARIABLES_ADMIN で、それより前のバージョンだとSYSTEM_VARIABLES_ADMINまたはSUPERが必要とある。

んー?よくわからんな・・・。

何が変わったんだ?

  • まず、8.0.25まではinnodb_strict_mode のセッション値を変えるのにどんな権限が必要なのかわかりにくい。
    • SESSION_VARIABLES_ADMINだけなの?
    • SESSION_VARIABLES_ADMIN or SYSTEM_VARIABLES_ADMIN or SUPER なの?
  • その上で8.0.26で必要な権限が何かハッキリとわからん。
    • 制限されたってのはどういうこと?
  • SESSION_VARIABLES_ADMINはおそらくセッション値を変えるのに必要なんだろうが、SYSTEM_VARIABLES_ADMIN、SUPERは8.0.14〜8.0.25で使える?使えない?がわからん。

ってわけで、ちとその3つ+1(USAGE)の権限でユーザー作って8.0.25と8.0.26で確認してみることに。

検証

検証用ユーザーとその権限

SUPER権限のユーザー

CREATE USER 'strict_super'@'%' IDENTIFIED BY 'xxxxxxxx';
grant SUPER on *.* to 'strict_super'@'%';

SESSION_VARIABLES_ADMIN権限のユーザー

CREATE USER 'ss_var_admin'@'%' IDENTIFIED BY 'xxxxxxxx';
grant SESSION_VARIABLES_ADMIN on *.*  to 'ss_var_admin'@'%';

SYSTEM_VARIABLES_ADMIN権限のユーザー

CREATE USER 'sys_var_admin'@'%' IDENTIFIED BY 'xxxxxxxx';
grant SYSTEM_VARIABLES_ADMIN on *.*  to 'sys_var_admin'@'%';

USAGE権限のユーザー

CREATE USER 'usage_user'@'%' IDENTIFIED BY 'xxxxxxxx';
grant USAGE on *.* to 'usage_user'@'%';

(※パスワードのxxxxxxxxの部分は適当に入れてね)

検証作業

8.0.25

SUPER権限のユーザー

$ mysql -ustrict_super -pxxxxxxxx -h127.0.0.1 -P8025
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.25-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.01 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.00 sec)

変更できる。(ほうほう)

SESSION_VARIABLES_ADMIN権限のユーザー

$ mysql -uss_var_admin -pxxxxxxxx -h127.0.0.1 -P8025
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 8.0.25-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.00 sec)

変更できる。(そらそう)

SYSTEM_VARIABLES_ADMIN権限のユーザー

$ mysql -usys_var_admin -pxxxxxxxx -h127.0.0.1 -P8025
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 8.0.25-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.00 sec)

変更できる。(まあ、そうか)

USAGE権限のユーザー

$ mysql -uusage_user -pxxxxxxxx -h127.0.0.1 -P8025
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.25-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.00 sec)

なんや、お前でもできるんやないか!?

SUPERとかなんとか言ってたのはアレ一体なんやったんや・・・。

というわけで、8.0.25でも実はSESSION_VARIABLES_ADMIN 以外にSYSTEM_VARIABLES_ADMINまたはSUPER、というかUSAGEでもセッションでの変更が可能だとわかった。

さて、問題の8.0.26である。

8.0.26

SUPER権限のユーザー

$ mysql -ustrict_super -pxxxxxxxx -h127.0.0.1 -P8026
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.26-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
ERROR 1227 (42000): Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN or SESSION_VARIABLES_ADMIN privilege(s) for this operation
mysql> set session innodb_strict_mode = OFF;
ERROR 1227 (42000): Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN or SESSION_VARIABLES_ADMIN privilege(s) for this operation

Oh... SUPERだと無理になってる!

コメントに

you need (at least one of) the SYSTEM_VARIABLES_ADMIN or SESSION_VARIABLES_ADMIN privilege(s) for this operation

とあるので、その2つのどっちかなら行けるってことか。

SESSION_VARIABLES_ADMIN権限のユーザー

$ mysql -uss_var_admin -pxxxxxxxx -h127.0.0.1 -P8026
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.26-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.01 sec)

うん、OKだね。

SYSTEM_VARIABLES_ADMIN権限のユーザー

$ mysql -usys_var_admin -pxxxxxxxx -h127.0.0.1 -P8026
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 8.0.26-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.00 sec)

やっぱりOK

USAGE権限のユーザー

$ mysql -uusage_user -pxxxxxxxx -h127.0.0.1 -P8026
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 8.0.26-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
ERROR 1227 (42000): Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN or SESSION_VARIABLES_ADMIN privilege(s) for this operation
mysql> set session innodb_strict_mode = OFF;
ERROR 1227 (42000): Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN or SESSION_VARIABLES_ADMIN privilege(s) for this operation

デスヨネー!

こうなってくると

気になるのは8.0.13以前。どうなっているんだ?

SESSION_VARIABLES_ADMIN権限は無いので、それ以外で試す。

8.0.13

SUPER権限のユーザー

$ mysql -ustrict_super -ppassword -h127.0.0.1 -P8013
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 8.0.13 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.00 sec)

変更できる。(ドキュメント通り)

SYSTEM_VARIABLES_ADMIN権限のユーザー

$ mysql -usys_var_admin -ppassword -h127.0.0.1 -P8013
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 8.0.13 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.00 sec)

変更できる。(ドキュメント通り)

USAGE権限のユーザー

$ mysql -uusage_user -ppassword -h127.0.0.1 -P8013
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 14
Server version: 8.0.13 MySQL Community Server - GPL

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_strict_mode = ON;
Query OK, 0 rows affected (0.00 sec)

mysql> set session innodb_strict_mode = OFF;
Query OK, 0 rows affected (0.00 sec)

( ゚д゚)

(つд⊂)ゴシゴシ

(;゚д゚)

まとめ

つまりこういうこと

権限 8.0.13 8.0.25 8.0.26
SUPER 変更可 変更可 変更不可
SESSION_VARIABLES_ADMIN 変更可 変更可 変更可
SYSTEM_VARIABLES_ADMIN 変更可 変更可 変更可
USAGE 変更可 変更可 変更不可

リリースノートとドキュメントに

innodb_strict_modeのセッション値を変更する権限として「SESSION_VARIABLES_ADMIN か SYSTEM_VARIABLES_ADMIN をちゃんと指定してね 」

を書いてもらいつつ、8.0.14より前の〜、のくだりは直しじゃないか。

レポート出しとくか。

ちなみに

上の話はinnodb_strict_modeでの話ですのでご注意を。

$ mysql -ustrict_super -pxxxxxxxx -h127.0.0.1 -P8026
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 15
Server version: 8.0.26-commercial MySQL Enterprise Server - Commercial

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> set session innodb_parallel_read_threads = 1;
Query OK, 0 rows affected (0.00 sec)

最後に

尊敬するyoku0825さんからご指摘頂き、正確に把握できました。

本当にありがとうございます。

【MySQL】テーブルの断片化を確認しよう

はじめに

自分用にテーブルが断片化してるか否かを確認する方法を書いてみました。

もし他にこんなのあるよー、って話あれば教えてください。

SHOW TABLE STATUS

  • Data_freeを見ると良い
  • innodb_file_per_tableオプションが有効であるべき
mysql> SHOW TABLE STATUS FROM test\G
*************************** 1. row ***************************
           Name: t1
         Engine: InnoDB
        Version: 10
     Row_format: Dynamic
           Rows: 0
 Avg_row_length: 0
    Data_length: 98304
Max_data_length: 0
   Index_length: 16384
      Data_free: 0
 Auto_increment: 1015
    Create_time: 2020-11-19 12:38:12
    Update_time: 2020-11-19 12:47:15
     Check_time: NULL
      Collation: utf8mb4_0900_ai_ci
       Checksum: NULL
 Create_options: 
        Comment: 
1 row in set (0.01 sec)

SHOW TABLE STATUS 構文については以下のドキュメントに詳細がありますので、興味のある方は読んでみてください。

MySQL :: MySQL 5.6 Reference Manual :: 13.7.5.37 SHOW TABLE STATUS Statement

information_schema.tablesで確認

とりあえずの概算値ではあるが、100MB以上のdata_freeがあるようなテーブルの一覧を出してみる方法。

SELECT 
    table_schema, table_name, data_free/1024/1024 AS data_free_MB
FROM 
    INFORMATION_SCHEMA.TABLES 
WHERE 
    engine LIKE 'InnoDB'
 AND 
    data_free > 100*1024*1024;

INFORMATION_SCHEMA TABLES テーブルについては以下のドキュメントに詳細がありますので、興味のある方は読んでみてください。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 21.22 INFORMATION_SCHEMA TABLES テーブル

innodb_ruby

Ruby製のMySQL InnoDBテーブルの断片化を見ることができるツール。

インストールについてはここ参照

使い方のイメージ

$ innodb_space -f /home/takiida/git/mysql/bld/data/test/t1.ibd  space-extents-illustrate

【番外編】バッファプール上のデータのフラグメンテーションの見積もり

こちらはファイルではなく、バッファプール上のデータのフラグメンテーションを見るものです。

SELECT 
    table_name, index_name, AVG(data_size), COUNT(*)
FROM
    INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
WHERE
    table_name IS NOT NULL
GROUP BY table_name , index_name
HAVING COUNT(*) > 100
ORDER BY AVG(data_size) ASC
LIMIT 10;

INFORMATION_SCHEMA INNODB_BUFFER_PAGE テーブルについては以下のドキュメントに詳細がありますので、興味のある方は読んでみてください。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 21.29.16 INFORMATION_SCHEMA INNODB_BUFFER_PAGE テーブル

最後に

とりあえず5.6のでも問題ないから読みやすい日本語ドキュメントを選んでます。

MySQL8.0の日本語ドキュメント公開されたらリンクは差し替えようかなと思っとります。

SELECT ... FOR UPDATEとUPDATEでデッドロックが出る人へ

はじめに

最近は主に花粉症に悩まされており、目が痒くてたまりません。

また、娘の生活がガラッと変わったせいで、毎日貧乏ヒマ無しです。

そんな中、たまたま早起きできたので奮起して久々に書いてみました。

問題が起きる環境

  • MySQL8.0.17以前
  • transaction_isolationがREAD-COMMITTED
  • WHERE句の条件が一意ではない。(フルテーブルスキャンだと発生しやすくなる)
  • キーの値がたすきがけになってる
  • トランザクション開始+SELECT ...FOR UPDATE→UPDATEのようにロックを取っている
  • 先に実行されたトランザクションが、たすきがけになっているキー値の若い(っていうのかな?)方のロックを取る

何が起きるかと言うと、SELECT ...FOR UPDATEのWHERE句で抽出した行に対してロックを取ってるのに、 後から別セッションで実行されたSELECT ...FOR UPDATEのせいで、先取りしたほうがデッドロックして負けるというお話。

これ、世の中のシステムで意外と起きてそうだなーと思ったが、文章にするとわかりづらいので、具体例を記載しながら説明する。

詳細

準備

1.まず、こんなテストテーブルを構築。

mysql> use test;
mysql> show create table tu\G
*************************** 1. row ***************************
       Table: tu
Create Table: CREATE TABLE `tu` (
  `id` int(11) NOT NULL,
  `a` int(11) DEFAULT NULL,
  `b` varchar(10) DEFAULT NULL,
  `c` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `u` (`a`,`b`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

2.データはこちら

mysql> INSERT INTO tu VALUSE(1,1,'a','a'),(2,2,'c','2'),(3,3,'b','3'),(4,4,'d','4');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM tu;
+----+------+------+------+
| id | a    | b    | c    |
+----+------+------+------+
|  1 |    1 | a    | a    |
|  2 |    2 | c    | 2    |
|  3 |    3 | b    | 3    |
|  4 |    4 | d    | 4    |
+----+------+------+------+
4 rows in set (0.00 sec)

キーはPKがid、UKがa,bで作られ、データはbカラムのところでid=2と3で入れ子にしている。

(PKはaカラムとbカラムの組み合わせでもOK)

検証

1. 1つ目のトランザクションでSELECT...FOR UPDATEを行う。

3行目のデータを更新対象に見据えて、SELECT...FOR UPDATE文を実行する。

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM tu WHERE c = '3' FOR UPDATE;
+----+------+------+------+
| id | a    | b    | c    |
+----+------+------+------+
|  3 |    3 | b    | 3    |
+----+------+------+------+
1 row in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM tu WHERE c = '3' FOR UPDATE;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | tu    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using WHERE |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

ここではWHERE句の条件をインデックスを使わず、フルテーブルスキャンになるようにしている。

この時、どのようなロックが取得されているかと言うと、以下の通り。

> SELECT * FROM performance_schema.data_locks\G
*************************** 1. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140229171137104:1061:140229071664344
ENGINE_TRANSACTION_ID: 3593
            THREAD_ID: 47
             EVENT_ID: 13
        OBJECT_SCHEMA: test
          OBJECT_NAME: tu
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140229071664344
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140229171137104:4:4:7:140229071661352
ENGINE_TRANSACTION_ID: 3593
            THREAD_ID: 47
             EVENT_ID: 13
        OBJECT_SCHEMA: test
          OBJECT_NAME: tu
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140229071661352
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: 3
2 rows in set (0.00 sec)

テーブルに対し、インサートインテンションロック、対象行に対し、排他ロックがかかる。

(ちなみに、MySQL5.7以前だとperformance_schema.data_locksは無い)

2. 2つ目のトランザクションでもSELECT...FOR UPDATEを行う。

mysql> BEGIN;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM tu WHERE c = '2' FOR UPDATE;

待たされる。

この時、どのようなロックが取得されているかと言うと、以下の通り。

mysql> SELECT * FROM performance_schema.data_locks\G
*************************** 1. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140229171137968:1061:140229071670264
ENGINE_TRANSACTION_ID: 3595
            THREAD_ID: 48
             EVENT_ID: 16
        OBJECT_SCHEMA: test
          OBJECT_NAME: tu
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140229071670264
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 2. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140229171137968:4:4:3:140229071667384
ENGINE_TRANSACTION_ID: 3595
            THREAD_ID: 48
             EVENT_ID: 16
        OBJECT_SCHEMA: test
          OBJECT_NAME: tu
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140229071667384
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: 2
*************************** 3. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140229171137968:4:4:7:140229071667728
ENGINE_TRANSACTION_ID: 3595
            THREAD_ID: 48
             EVENT_ID: 16
        OBJECT_SCHEMA: test
          OBJECT_NAME: tu
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140229071667728
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: WAITING
            LOCK_DATA: 3
*************************** 4. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140229171137104:1061:140229071664344
ENGINE_TRANSACTION_ID: 3593
            THREAD_ID: 47
             EVENT_ID: 13
        OBJECT_SCHEMA: test
          OBJECT_NAME: tu
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: NULL
OBJECT_INSTANCE_BEGIN: 140229071664344
            LOCK_TYPE: TABLE
            LOCK_MODE: IX
          LOCK_STATUS: GRANTED
            LOCK_DATA: NULL
*************************** 5. row ***************************
               ENGINE: INNODB
       ENGINE_LOCK_ID: 140229171137104:4:4:7:140229071661352
ENGINE_TRANSACTION_ID: 3593
            THREAD_ID: 47
             EVENT_ID: 13
        OBJECT_SCHEMA: test
          OBJECT_NAME: tu
       PARTITION_NAME: NULL
    SUBPARTITION_NAME: NULL
           INDEX_NAME: PRIMARY
OBJECT_INSTANCE_BEGIN: 140229071661352
            LOCK_TYPE: RECORD
            LOCK_MODE: X,REC_NOT_GAP
          LOCK_STATUS: GRANTED
            LOCK_DATA: 3
5 rows in set (0.00 sec)

上の3つが2つ目のトランザクションによるロック。

"3. row" のロックが LOCK_STATUS: WAITING となっているのでこれにより待たされていることがわかる。

これだけを見ると、1つ目のトランザクションでは正常に後続のUPDATE文が通りそうなもんであるが、しかし・・・

3. 1つ目のトランザクションでUPDATEが失敗する

mysql> UPDATE tu SET c='c2' WHERE c = '3';
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

ちなみに上記のデッドロック、もし2つ目のトランザクションの条件(where c = '2')を先に実行した場合はデッドロックが発生しない。

原因

リリースノートにあるコレ

InnoDB: A deadlock was possible when a transaction tries to upgrade a record lock to a next key lock. (Bug #23755664, Bug #82127)

解決方法

3つあって

  • MySQL8.0.18以降にする
  • transaction_isolationをREPEATABLE-READにする
  • 更新対象を一意にする

根治するならバージョンアップ一択なんですが、バージョンいきなりやれって言われてもツライと思うし、

transaction_isolation変えるなんて、それもまたシステムへの影響多いだろうから、

まずは更新対象をできるだけ絞る、可能なら一意にするってところから始めてくれればかと。

もし、EXPLAIN取ってtypeがALLなんて出てたら、それを潰すところからですね。

インデックス張りましょう。抽出対象を絞れるようにしましょう。

最後に

そういえば、2月15日で勤続1年になりました。

チームのメンバー、イルカさん関係者の皆さん、外部のイルカ大好きな皆様、そしてお客様に恵まれ、非常にやりがいもあり成長させていただき、充実した一年でした。

まだまだ力不足でご迷惑をおかけすることもあるかもしれませんが、今後ともよろしくお願いします。

参照情報

bugs.mysql.com

適応ハッシュインデックスについて

はじめに

こないだのAdvent Calendar用の記事で適応ハッシュインデックス(AHI)について少し書いたんだけど、今日はそもそもそれってどうやって使ったり見たりするの?って話です。

適応ハッシュインデックスとは?(おさらい)

  • InnoDBのインデックスはクラスタ化されていて、主キーのリーフノードにデータが一緒に格納されている。
  • そのため、主キーによる検索は高速だが、セカンダリインデックスを用いた検索では、セカンダリインデックスから条件に合致するインデックスエントリの主キーの値を取得し、改めて主キーを検索するという2段階の検索が生じるため、やや遅い。
  • それに対し、バッファプール上にハッシュテーブルを動的に作成し、主キーの検索を効率化させるようにしたのが適応ハッシュインデックス。

詳しい説明については、下記のマニュアル参照

MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.2.13.6 適応型ハッシュインデックス

有効化するには?

以下のシステム変数により、オンラインでON/OFFの切り替えが可能。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.12 InnoDB の起動オプションおよびシステム変数

デフォルトは?

ONです。

SET_VARヒント使える?(8.0の話)

使えません

SET_VARヒント→ MySQL :: MySQL 8.0 Reference Manual :: 8.9.3 Optimizer Hints 参照

モニタリングを有効化するには

innodb_monitor_enableにmodule_adaptive_hashを設定する。

mysql> SET GLOBAL innodb_monitor_enable='module_adaptive_hash';

MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.14.6 InnoDB INFORMATION_SCHEMA メトリックテーブル

AHIをクエリで確認する

AHIを使っているかどうか

以下のようなクエリで確認することが可能

mysql> SELECT name, count FROM information_schema.INNODB_METRICS WHERE name LIKE '%adaptive%';

どの程度の適応ハッシュインデックスがバッファプールに存在するか

以下のようなクエリで確認することが可能

mysql> SELECT SUM(IS_HASHED = 'YES') HASHED_PAGES, COUNT(1) TOTAL_PAGES FROM information_schema.INNODB_BUFFER_PAGE;

但し、上記クエリは実行に負荷が高いので、本番環境で実行するのはおススメできない。(検証環境でやろう) また、出力された結果は、ハッシュそのもののサイズではなく、これはハッシュが作成されたページ数であるためあくまで参考情報。

INNODB_BUFFER_PAGE テーブルについては以下のドキュメント参照。 MySQL :: MySQL 5.6 リファレンスマニュアル :: 21.29.16 INFORMATION_SCHEMA INNODB_BUFFER_PAGE テーブル

ヒット率

以下のようなクエリで確認することが可能

mysql> SELECT ahi_hits, ahi_miss, 100 * ahi_hits / ahi_miss AS ahi_hit_pct
         > FROM (SELECT
         > (SELECT count FROM information_schema.INNODB_METRICS WHERE NAME = 'adaptive_hash_searches') AS ahi_hits,
         > (SELECT count FROM information_schema.INNODB_METRICS WHERE NAME = 'adaptive_hash_searches_btree') AS ahi_miss) t;

とはいえ、有効にしたとしてもワークロード上、必ず早くなるというわけではないため、切り替えを行う場合は確認が必要。

INNODB_METRICS テーブルについては以下のドキュメント参照。 MySQL :: MySQL 5.6 リファレンスマニュアル :: 21.29.19 INFORMATION_SCHEMA INNODB_METRICS テーブル

その他

B ツリーインデックスとハッシュインデックスの比較

MySQL :: MySQL 5.6 リファレンスマニュアル :: 8.3.8 B ツリーインデックスとハッシュインデックスの比較

を読もう。

おわりに

これも自分用のメモみたいなもんなんで殴り書きレベルです。

なんか新しく気づいたことあれば追記します。

読みにくかったらごめんなさい。