この記事は MySQL 8.0: all you need to know about SDI (2021/8/12掲載)の翻訳版です。本記事に関する最新情報は別途ご確認ください。
MySQL8.0 ではMyISAMテーブルに .frm ファイルが.sdi ファイルに置き換わりました。(参照).
しかし、このファイルは何なのでしょうか?MyISAMテーブル以外の用途に使用できるのでしょうか?…これらの疑問について確認しながら.sdiファイルについてより深く理解しましょう。
SDIとは何の略でしょうか?
SDI は Serialized Dictionary Information(シリアライズディクショナリ情報) の略です。
ご存知のように、MySQL 8.0では、テーブルのメタデータやその構造を保存する方法が、(InnoDB内の)新しいトランザクションデータディクショナリに置き換えられました。
さらに、これらの情報はInnoDBテーブルスペースの一部として追加されるため、メタデータとデータは一緒に保存されます。
この機能をサポートしていないストレージエンジンでは、外部ファイルすなわちSDIファイルが作成されます。例えばMyISAMテーブルの場合です。
どのように見えるのでしょうか?
ストレージエンジンがテーブルのメタデータを保存する機能を持っていない場合、SDIファイルが作成されます。それはどのようなものでしょうか?
SDIファイルの実体はコンパクトなJSONファイルで、ファイル名はテーブル名とテーブルIDで構成されます。
以前の記事で紹介したテーブルを例にとると、ファイルシステム上では、SDIファイルは次のようになります。
[root@imac my_isam_db]# ls -l *.sdi -rw-r----- 1 mysql mysql 3600 Aug 2 12:49 t1_5017.sdi
5017 はテーブルIDになります。
実際には、ディクショナリのオブジェクトID(OID)を文字列で表現したものです。OIDは一意性を保証するもので、複数のテーブルが同じ名前にマッピングされる可能性があるため、必要なものです。
では実際のJSONがどのようなものか見てみましょう。
{
"mysqld_version_id": 80026,
"dd_version": 80023,
"sdi_version": 80019,
"dd_object_type": "Table",
"dd_object": {
"name": "t1",
"mysql_version_id": 80026,
"created": 20210802104936,
"last_altered": 20210802104936,
"hidden": 1,
"options": "avg_row_length=0;key_block_size=0;keys_disabled=0;pack_record=1;stats_auto_recalc=0;stats_sample_pages=0;",
"columns": [
{
"name": "id",
"type": 4,
"is_nullable": false,
"is_zerofill": false,
"is_unsigned": true,
"is_auto_increment": true,
"is_virtual": false,
"hidden": 1,
"ordinal_position": 1,
"char_length": 10,
"numeric_precision": 10,
"numeric_scale": 0,
"numeric_scale_null": false,
"datetime_precision": 0,
"datetime_precision_null": 1,
"has_no_default": false,
"default_value_null": false,
"srs_id_null": true,
"srs_id": 0,
"default_value": "AAAAAA==",
"default_value_utf8_null": true,
"default_value_utf8": "",
"default_option": "",
"update_option": "",
"comment": "",
"generation_expression": "",
"generation_expression_utf8": "",
"options": "interval_count=0;",
"se_private_data": "",
"engine_attribute": "",
"secondary_engine_attribute": "",
"column_key": 2,
"column_type_utf8": "int unsigned",
"elements": [],
"collation_id": 8,
"is_explicit_collation": false
},
{
"name": "name",
"type": 16,
"is_nullable": true,
"is_zerofill": false,
"is_unsigned": false,
"is_auto_increment": false,
"is_virtual": false,
"hidden": 1,
"ordinal_position": 2,
"char_length": 20,
"numeric_precision": 0,
"numeric_scale": 0,
"numeric_scale_null": true,
"datetime_precision": 0,
"datetime_precision_null": 1,
"has_no_default": false,
"default_value_null": true,
"srs_id_null": true,
"srs_id": 0,
"default_value": "",
"default_value_utf8_null": true,
"default_value_utf8": "",
"default_option": "",
"update_option": "",
"comment": "",
"generation_expression": "",
"generation_expression_utf8": "",
"options": "interval_count=0;",
"se_private_data": "",
"engine_attribute": "",
"secondary_engine_attribute": "",
"column_key": 1,
"column_type_utf8": "varchar(20)",
"elements": [],
"collation_id": 8,
"is_explicit_collation": false
},
{
"name": "inserted",
"type": 18,
"is_nullable": false,
"is_zerofill": false,
"is_unsigned": false,
"is_auto_increment": false,
"is_virtual": false,
"hidden": 1,
"ordinal_position": 3,
"char_length": 19,
"numeric_precision": 0,
"numeric_scale": 0,
"numeric_scale_null": true,
"datetime_precision": 0,
"datetime_precision_null": 0,
"has_no_default": false,
"default_value_null": false,
"srs_id_null": true,
"srs_id": 0,
"default_value": "AAAAAA==",
"default_value_utf8_null": false,
"default_value_utf8": "CURRENT_TIMESTAMP",
"default_option": "CURRENT_TIMESTAMP",
"update_option": "",
"comment": "",
"generation_expression": "",
"generation_expression_utf8": "",
"options": "interval_count=0;",
"se_private_data": "",
"engine_attribute": "",
"secondary_engine_attribute": "",
"column_key": 1,
"column_type_utf8": "timestamp",
"elements": [],
"collation_id": 8,
"is_explicit_collation": false
}
],
"schema_ref": "my_isam_db",
"se_private_id": 18446744073709552000,
"engine": "MyISAM",
"last_checked_for_upgrade_version_id": 0,
"comment": "",
"se_private_data": "",
"engine_attribute": "",
"secondary_engine_attribute": "",
"row_format": 2,
"partition_type": 0,
"partition_expression": "",
"partition_expression_utf8": "",
"default_partitioning": 0,
"subpartition_type": 0,
"subpartition_expression": "",
"subpartition_expression_utf8": "",
"default_subpartitioning": 0,
"indexes": [
{
"name": "PRIMARY",
"hidden": false,
"is_generated": false,
"ordinal_position": 1,
"comment": "",
"options": "flags=0;",
"se_private_data": "",
"type": 1,
"algorithm": 2,
"is_algorithm_explicit": false,
"is_visible": true,
"engine": "MyISAM",
"engine_attribute": "",
"secondary_engine_attribute": "",
"elements": [
{
"ordinal_position": 1,
"length": 4,
"order": 2,
"hidden": false,
"column_opx": 0
}
]
}
],
"foreign_keys": [],
"check_constraints": [],
"partitions": [],
"collation_id": 8
}
}
ご覧のように、このSDIファイルには多くの情報が含まれています。
参考までに、テーブル作成時のコマンドは以下の通りです。
CREATE TABLE `t1` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `inserted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1
SDI ファイルは MyISAM でのみ使用されるのでしょうか?
SDIファイルはIMPORT TABLE FROMステートメントを使用して、MySIAMテーブルをMySQL 8.0 サーバーにコピーするために使用することができます。
また、SDIファイルはメタデータ情報を埋め込むことができない他のストレージエンジンにも使用されます。現在はInnoDB と NDB だけが SDI ファイルを必要としないストレージエンジンになります。
以下のように、CSVテーブルを作成した場合、そのテーブルもSDIを持つことになります。
CREATE TABLE `t2` ( `id` int unsigned NOT NULL, `name` varchar(20) NOT NULL DEFAULT '', `inserted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=CSV DEFAULT CHARSET=latin1 [root@imac my_isam_db]# ls -l t2* -rw-r----- 1 mysql mysql 3268 Aug 11 13:27 t2_5037.sdi -rw-r----- 1 mysql mysql 35 Aug 11 13:27 t2.CSM -rw-r----- 1 mysql mysql 0 Aug 11 13:27 t2.CSV
もちろん、SDIファイルからもその情報を確認することが可能です。
[root@imac my_isam_db]# cat t2_5037.sdi | jq ."dd_object"."engine" "CSV"
SDI ファイルはメタデータの冗長性を提供します。また、InnoDBテーブルの場合でも、例えばデータディクショナリが使用できなくなった際にオブジェクトメタデータをInnoDBテーブルスペースファイルから直接抽出することが可能です。
SDIとInnoDB
InnoDBテーブルの場合、SDI情報はibd2sdiというツールを使ってテーブルスペースから抽出することができます。
ibd2sdi は file-per-table テーブルスペースファイル (*.ibd ファイル)、general tablespaceファイル (*.ibd files)、system tablespaceファイル (ibdata* files)、およびデータディクショナリテーブルスペース (mysql.ibd)に対して実行できます。一時テーブルスペースまたは undo テーブルスペースでの使用はサポートされていません。
では、InnoDBで試してみましょう。先ほどと同じように、InnoDBをストレージエンジンとして使用する別のテーブル((t3))を作成すると、実際にスキーマのディレクトリに1つの.ibdファイルが確認できます。
[root@imac my_isam_db]# ls t1_5017.sdi t1.MYD t1.MYI t2_5037.sdi t2.CSM t2.CSV t3.ibd
そこからSDIファイルを生成します。
# ibd2sdi t3.ibd -d t3.sdi
生成したSDIファイルを解析することができますが、MySQLでは必須ではありません。これはメタデータのコピーにしかすぎません。
既存の SDI ファイルを手動で変更することはできますか?
もちろん、これは推奨されません。テーブルがすでにMySQLに登録された後に.sdiファイルを削除または修正した場合、すでにデータディクショナリの一部となっているため、MySQLサーバーは手動での変更は必要としません。
SDI ファイルを必要とするエンジンの場合はテーブルを変更するたびに、古いファイルは異なる OID を持つ新しいファイルに置き換えられます。

