MySQL Blog Archive
For the latest blogs go to blogs.oracle.com/mysql
MySQL 8.0: all you need to know about SDI

We recently saw that .frm files have been somewhat of replaced for MyISAM tables in MySQL 8.0 (see this post).

However, what are those files ? Can they be used for something else than MyISAM tables ? … Let’s try to answer those questions and get more familiar with the .sdi files.

What does SDI stand for ?

SDI acronym stands for Serialized Dictionary Information.

As you may know already, MySQL 8.0 replaced the old way to store the metadata of tables, their structure, into the new transactional Data Dictionary (in InnoDB).

Additionally, that information is also part any InnoDB tabespace , its is appended to the tablespace, so the meta data and data are bundled together.

For storage engine not supporting this feature, an external file, the actual SDI is created. This is the case for example for MyISAM tables.

What do they look like ?

So we know that for storage engine not having the capability to store the metadata of the tables, a SDI file is created. What does it look like ?

In fact the SDI file is a compact JSON file. It’s name is formed by the table's name and the table’s id.

If we take the example table from the previous post, on the file system, the SDI file looks like this:

[root@imac my_isam_db]# ls -l *.sdi
-rw-r----- 1 mysql mysql 3600 Aug  2 12:49 t1_5017.sdi

5017 is the table’s hidden id.

In fact, it’s a string representation of the OID of the dictionary object. The OID ensures uniqueness, which is required since several tables may map to the same name.

Now let’s have a look at what that JSON looks like:

{
  "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
  }
}

As you can see, this SDI file contains a lot of information. Just for reference this was the table’s creation statement:

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

Are SDI files used only with MyISAM ?

That SDI file can be used to copy MySIAM tables around MySQL 8.0 servers using the specific statement IMPORT TABLE FROM.

The SDI files are also used for any other Storage Engine that is not able to embed the metadata information. Currently only InnoDB and NDB don’t require any SDI file.

If you create a CVS table, it will also have a 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

And of course we can check that information from the SDI file too:

[root@imac my_isam_db]# cat t2_5037.sdi | jq ."dd_object"."engine"
<strong>"CSV"</strong>

The SDI files provides metadata redundancy. And even for InnoDB tables it can be useful if for example the data dictionary becomes unavailable, object metadata can be extracted directly from InnoDB tablespace files.

SDI Information and InnoDB

For InnoDB tables, the SDI information can be extracted from the tablespace using a tool called ibd2sdi.

ibd2sdi can be run on file-per-table tablespace files (*.ibd files), general tablespace files (*.ibd files), system tablespace files (ibdata* files), and the data dictionary tablespace (mysql.ibd). It is not supported for use with temporary tablespaces or undo tablespaces.

Let’s try it then with InnoDB. I just created another table ((t3) like the previous ones but using InnoDB as storage engine and indeed in the schema’s directory we can see this single .ibd file:

[root@imac my_isam_db]# ls
t1_5017.sdi  t1.MYD  t1.MYI  t2_5037.sdi  t2.CSM  t2.CSV  <strong>t3.ibd</strong>

Now we can generate a SDI file from it:

# ibd2sdi t3.ibd -d t3.sdi

We can parse the new created SDI file but it’s not required by MySQL, it's just an extra copy of the metadata.

Can I modify manually an existing SDI file ?

Of course, this is not recommended. However if you delete or modify a .sdi file after the table was already in MySQL, the server won’t require it as the structure is already part of the Data Dictionary.

Every time you modify a table using an engine that requires a SDI file, a new file with a different OID number replaces the eventual previous one.