読者です 読者をやめる 読者になる 読者になる

MySQL のストレージエンジンについて調べた

mysql

なぜか忘れたけど MySQL のストレージエンジンについて調べたので書いておく。

はじめに断っておくと MySQL 5.6 以降について書いています。

MySQL の「ストレージエンジン」とはなにか?

ストレージエンジンとはInnoDBのことである。

MySQLはプラガブルな(置き換え可能な)ストレージエンジンの仕組み(アーキテクチャ)を備えている。何も考えなければそれはInnoDBであり、通常はそのままでよい。ストレージエンジンにはそれぞれ特徴があるので、特殊な使い方(ユースケース)を求めている場合、最適なストレージエンジンが他にあるかもしれないというのを頭の片隅に覚えておきたい。

自分が使っているMySQLがサポートしているストレージエンジンを知りたい場合、SHOW ENGINESコマンドを実行する。ちなみに手元にあるMySQL 5.6.13で実行したら以下のようになった。

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)

(PERFORMANCE_SCHEMAもストレージエンジンなのか...)

それぞれのストレージエンジンの特徴は MySQL :: MySQL 5.6 Reference Manual :: 15 Alternative Storage Engines に詳しく書いてある。

ストレージエンジンの種類はテーブルを作るときに指定することができる。CREATE TABLE 文の ENGINE オプションに使いたいストレージエンジンの名前を書けばよい。例えば BLACKHOLE を使いたいならばこうなる。

CREATE TABLE t1 (
  id INT NOT NULL AUTO_INCREMENT,
  col1 INT NOT NULL,
  col2 INT NOT NULL,
  PRIMARY KEY (id)
) ENGINE=BLACKHOLE;

既存のテーブルのストレージエンジンを変更したい場合はALTER TABLEで可能だ。たとえば MEMORY に変更したい場合はこうする。

ALTER TABLE t1 ENGINE=MEMORY;

アーキテクチャ

次にストレージエンジンのアーキテクチャを俯瞰したい。

f:id:takatoshiono:20150625202604p:plain

ここで抽象ストレージエンジン I/F と書いたところは実際には以下の2つである。

  • handler 抽象クラス
  • handlerton 構造体

これは sql/handler.h で定義され、sql/handler.cc で一部実装されている。

ストレージエンジンではこれを実装すればよい。例えば InnoDB では以下のファイルになる。

ストレージエンジンを自作してみる

ストレージエンジンは自分で作ることができるので試してみたい。

まず実装するストレージエンジンの要件を以下のように決めた。

  • SQLを使ってCSVファイルからデータを読み出すことができる
  • データの書き込みはできない

MySQL Internals Manual :: 22 Writing a Custom Storage Engine :: 22.2 Overview にも、まずリードオンリーのストレージエンジンから始めて、次に INSERT, UPDATE, DELTE をサポートして、その後にインデックスやトランザクションなどをサポートするのがよいみたいに書いてあった。

名前

MYCSV ストレージエンジンにした。

Example から始める

22.3 Creating Storage Engine Source Files によると EXAMPLE storage engine というのがあるので、ここから始めるのがいいらしい。

ビルドできるようになる

ファイルを作ってまずやることは以下の2つだ。

  1. 動かし方(ビルド方法)を知る
  2. ちゃんと動くか確かめる

自分のコードを書く前に「いまそこにあるコード」がちゃんと動くことを確認するのは大事なことだ。

詳細は ビルドできるようにする · Issue #1 · takatoshiono/mysql-mycsv に書いたけど、この時点で以下の状態だった。

  • テーブルが作れる
  • INSERT が成功する(ように見える)
  • SELECT すると空っぽ

インターフェースを確認する

実装を始める前に何を実装すればいいか知る必要があるので、テーブルからデータを読み取るために必要なストレージエンジンインターフェースを確認しておく。

MySQL :: MySQL Internals Manual :: 22 Writing a Custom Storage Engine の 22.10 Implementing Basic Table Scanning までをざっと読む。

初期化フェーズ

handler クラスのインスタンスを作る。

テーブルの作成

テーブルを作るときには handler インスタンスの create メソッドが呼ばれる。これは handler 抽象クラスの以下の純粋仮想関数を実装したものだ。

virtual int create(const char *name, TABLE *form, HA_CREATE_INFO *info)=0;

MySQL :: MySQL Internals Manual :: 22.8 Creating Tables

テーブルのオープン

同じく open メソッドが呼ばれる。これはキャッシュされるので毎回呼ばれるわけではない(と CSV ストレージエンジンのソースコードに書いてあった)。

virtual int open(const char *name, int mode, uint test_if_locked)=0;

MySQL :: MySQL Internals Manual :: 22.9 Opening a Table

テーブルの読み取り

例えば CSV ストレージエンジン(tina という名前)で9行読むときの流れはこうなるらしい。

ha_tina::store_lock
ha_tina::external_lock
ha_tina::info
ha_tina::rnd_init
ha_tina::extra - ENUM HA_EXTRA_CACHE   Cache record in HA_rrnd()
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::extra - ENUM HA_EXTRA_NO_CACHE   End caching of records (def)
ha_tina::external_lock
ha_tina::extra - ENUM HA_EXTRA_RESET   Reset database to after open

MySQL :: MySQL Internals Manual :: 22.10 Implementing Basic Table Scanning

実装する

詳解MySQL という本がある。少し古い本なのだが、この本にストレージエンジンを実装するという章があるので(とても)参考にした。ソースコードダウンロードできるので便利。

成果物がこちらです。

takatoshiono/mysql-mycsv · GitHub

実装するときに苦労した点だけ書いておく。

参考リンク

詳解 MySQL

詳解 MySQL