InnoDB Data Dictionary--施洪寶

一. 基礎知識

  1. 本文使用的Mysql版本: 8.0.12-debug
  2. 本文用到的Linux命令: xxd
  3. 本文須要使用到的知識點: Mysql 數據頁存儲, 能夠參見 https://segmentfault.com/a/1190000037436803

1.1 問題

  1. Data Dictironary是什麼?
  • Data Dictironary(DD, 數據字典)是有關數據庫對象的合集, 例如表、視圖、索引等, 能夠看作是數據庫的元信息。換句話說, 數據字典存儲了有關表結構的信息, 每一個表具備的列, 表的索引等。

2.系統表是什麼? 跟本身建立的表有何不一樣?html

  • 系統表有不少, 常見的有mysql.schemata,mysql.tables, mysql.indexes
  • 咱們建立的表的元信息是放到系統表中的
  • 在內存中, 這些元信息以對象的方式提供給外部使用, 好比說, 建立一個表, 內存中會建立這個表的數據字典對象, 系統表以及咱們建立的表都會有本身的數據字典對象
  • 能夠認爲系統表的元信息就存儲在本身的數據字典對象中, 這些信息會被序列化到磁盤的mysql.ibd文件中

3.DD存儲在哪些地方?python

這裏是針對Mysql 8的數據字典,mysql

  • 數據字典信息須要持久化, 存儲在mysql.ibd文件中, 使用專門的表空間id
  • 在每一個獨立的表空間中, 也備份了一份這個表空間相關的dd對象序列化信息
  • 系統表空間, 也就是ibdata1文件中, 並無存儲dd對象的相關信息

1.2 DD存儲

Mysql 8以前, 數據字典存儲結構以下圖,sql

數據字典

從圖中能夠看出, DD信息存儲在多個地方,數據庫

  • 部分數據存儲在文件中
  • 部分數據存儲在mysql系統表中
  • InnoDB系統表也存儲了部分數據

這種存儲方式存在如下問題:json

  1. 數據存儲在多個地方, 難以維護管理
  2. MyISAM系統表容易損壞
  3. 不支持原子操做

Mysql 8 對數據字典進行了從新設計, 而且使用InnoDB存儲,segmentfault

數據字典-Mysql 8

  • 將原來存儲數據字典的文件所有刪除, 統一放到數據字典表空間中
  • 對於原來使用MyISAM存儲的系統表, 所有替換爲InnoDB存儲, 爲實現原子DDL提供了可能性

1.3 如何查看數據字典

  1. 經過命令行鏈接Mysql服務器查看
SET SESSION debug='+d,skip_dd_table_access_check';
SELECT name, schema_id, hidden, type FROM mysql.tables where schema_id=1 AND hidden='System';

能夠看到DD中存儲了不少系統表,服務器

+------------------------------+-----------+--------+------------+
| name                         | schema_id | hidden | type       |
+------------------------------+-----------+--------+------------+
| catalogs                     |         1 | System | BASE TABLE |
| character_sets               |         1 | System | BASE TABLE |
| collations                   |         1 | System | BASE TABLE |
| columns                      |         1 | System | BASE TABLE |
| dd_properties                |         1 | System | BASE TABLE |
| events                       |         1 | System | BASE TABLE |
| index_stats                  |         1 | System | BASE TABLE |
| indexes                      |         1 | System | BASE TABLE |
| schemata                     |         1 | System | BASE TABLE |
| tables                       |         1 | System | BASE TABLE |
| tablespace_files             |         1 | System | BASE TABLE |
| tablespaces                  |         1 | System | BASE TABLE |
+------------------------------+-----------+--------+------------+
  • 這裏咱們僅列出了一部分, InnoDB還存儲了不少其餘的系統表
  • 這些系統表存儲了各類元數據, columns存儲了表的列信息, indexes則存儲了表的索引信息, schemata存儲了數據庫的信息。

2.經過 ibd2sdi 工具查看工具

ibd2sdi test.ibd
  • tips: 能夠經過utilities/ibd2sdi.cc文件, 查看反序列化過程, 進而能夠看出sdi頁面存儲結構

1.4 Serialized Dictionary Information(SDI)

  1. SDI是什麼?
  • SDI, 字典序列化信息, 也就是將數據字典中的對象序列化後的數據

2.SDI如何組織?學習

  • DD中包含不少的數據字典對象, 這些對象的SDI數據以B+樹的方式進行組織
  • SDI數據基本都是壓縮後存儲的, 壓縮方式使用的是zlib

3.SDI舉例

{
    "mysqld_version_id":80012,
    "dd_version":80012,
    "sdi_version":1,
    "dd_object_type":"Table",
    "dd_object":{
        "name":"x",
        "columns":[
            {
                "name":"id",
                "type":4,
                ...
            },
            {
                "name":"DB_TRX_ID",
                "type":10,
                ...
            },
            {
                "name":"DB_ROLL_PTR",
                "type":9,
                ...
            }
        ],
        ...
        "indexes":[
            {
                "name":"PRIMARY",
                "hidden":false,
                ...
            }
        ],
        ...
    }
}
  • 能夠看到, SDI中存儲了這個表的元信息, 好比說這個表的列組成, 索引信息等。

二. SDI存儲頁示例

上文中, 咱們說過在每一個表的獨立表空間中, 存儲了這個表相關的DD對象序列化後的信息。在這一節, 咱們學習如何查看SDI信息。

  1. 咱們首先創建一個表
CREATE TABLE `x` (
  `id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
  • 表所在的庫是hbshi

2.查看這表的獨立表空間文件, 經過 xxd x.ibd x.txt 查看這個表空間的數據頁, 這裏咱們主要看第4頁, 這1頁存儲了這個表相關的數據字典序列化信息,

000c000: 723e 3b3c 0000 0003 ffff ffff ffff ffff  r>;<............
000c010: 0000 0000 0128 06fc 45bd 0000 0000 0000  .....(..E.......
000c020: 0000 0000 0004 0002 04d2 8004 0000 0000  ................
000c030: 0172 0001 0001 0002 0000 0000 0000 0000  .r..............
000c040: 0000 ffff ffff ffff ffff 0000 0004 0000  ................
000c050: 0002 00f2 0000 0004 0000 0002 0032 0100  .............2..
000c060: 0201 0f69 6e66 696d 756d 0003 000b 0000  ...infimum......
000c070: 7375 7072 656d 756d cb80 0000 10ff f100  supremum........
000c080: 0000 0200 0000 0000 0000 0900 0000 0016  ................
........
........
000fff0: 0000 0000 0070 0063 723e 3b3c 0128 06fc  .....p.cr>;<.(..

對於一個表空間而言, 可能會有多個數據字典對象, 這些對象序列化後會以B+樹的方式組織, 咱們看一下具體的存儲結構,

總體頁存儲結構:

  • 最小記錄: 記錄頭[00c05e, 00c062], 具體數據[00c063, 00c06a]
  • 最大記錄: 記錄頭[00c06b, 00c06f], 具體數據[00c070, 00c077]
  • 第1條記錄: 2字節的內容長度[00c078, 00c079]; 5字節的記錄頭[00c07a, 00c07e]; 記錄內容[00c07f, 00c16a]。
  • 第2條記錄: 2字節的內容長度[00c16b, 00c16c], 5字節的記錄頭[00c16d, 00c171], 記錄的數據[00c172, 00c4d1]

咱們再看下每一個記錄的具體存儲:

  • 長度: 1或者2個字節的長度字段, 說明內容長度
  • 5個字節的記錄頭
  • 33個字節的記錄說明
  • 記錄的具體內容, 記錄頭前面的1或者2個字節就是說明這個記錄的內容長度的

記錄說明:

  • 4個字節的類型信息
  • 8個字節的id
  • 6個字節的事務id
  • 7個字節的回滾指針
  • 4個字節的非壓縮長度
  • 4個字節的壓縮長度

存儲結構以下圖所示,
SDI存儲頁

3.SDI記錄遍歷流程

  • 從最小記錄計算第1條記錄, 00c063 + 010f = 00c172
  • 計算第2條記錄, 00c172 + ff0d = 00c07f
  • 計算第3條記錄: 00c07f + fff1 = 00c070

注意: 遊標以每一個記錄的內容開始, 例如最小記錄的開始位置爲00c063, 而不是00c05e。計算的下一個記錄位置, 也是內容開始的位置。

4.如何查看SDI壓縮後的數據

  • 首先經過bin/ibd2sdi工具, 將ibd文件中的sdi信息打印
  • 從打印中的信息中, 選擇其中一項
  • 從選中的一項中抽出object字段, 將其壓縮, 這裏咱們使用python腳本進行壓縮, 壓縮方式使用zlib
#!/usr/bin/env python
# -*- coding=utf-8 -*-
#
import os
import sys
import json
import time
import datetime
import hashlib
import zlib

reload(sys)
sys.setdefaultencoding("utf-8")

def help():
    f = open("./test.data")
    l = f.readline()
    d = zlib.compress(l)
    f2 = open("./tmp.data", 'w+')
    f2.write(d)

help()
  • 對比壓縮後的數據以及表空間存儲的數據

三. DD表空間

  1. InnoDB經常使用表空間
  • 表空間佔用4個字節, 最大值爲0xffff ffff, 這個表空間是無效的, 沒有使用
  • 0xffff fffe 是data dicitonary的表空間, 也就是mysql.ibd
  • 0xffff fffd 是臨時表空間, 也就是ibtmp1.ibd
  • [0xffff fffc, 0xffff fff0]是爲日誌準備的
  • [0xffff ffef, 0xffff ff70]是undo log
  • [0x0000 0002, 0xffff ff6f]是能夠正常使用的表空間
  • 1是 sys/sys_config 表空間
  • 0是系統表空間, 也就是ibdata1

2.DD表空間存儲

image

  • DD表空間存儲結構與通常的獨立表空間存儲結構是相同的
  • 第4頁(page 3)是SDI存儲的root page, SDI以B+樹進行組織
  • 除了SDI信息外, 具體的元數據表也存儲在這個表空間中, 存儲方式與通常的表是同樣的。

四. 總結與思考

  1. 本文主要介紹了Mysql數據字典的概念以及數據字典的存儲, 這裏咱們簡單總結一下,
  • 系統表以及咱們建立的表, 元信息都存儲在數據字典中
  • 咱們本身建立的表的元信息存儲在系統表中, 同時也會序列化到本身的表空間中
  • 系統表的元信息, 存儲在系統表的數據字典對象中, 這些信息會被序列化到mysql.ibd文件中
  • SDI信息以B+樹的方式進行組織

2.思考

  • DD是數據庫對象的合集, Mysql server層以及InnoDB層都須要這些信息, 他們是如何具體操做的?
  • DDL的原子性是如何實現的?

五. 參考

  1. https://dev.mysql.com/doc/ref...
相關文章
相關標籤/搜索