數據庫原理系列一:存儲引擎(上)

0:數據庫架構 & 常見模塊

在這裏插入圖片描述

Q1:爲什麼是disk-oriented架構?

  • 磁盤很慢。那麼問題來了,磁盤慢爲啥還要用呢?
  • 磁盤便宜。磁盤比內存那不是便宜了一點啊。
  • 比內存大。數據往往很大,如果單純的就用內存,那麼多的數據存在哪。
  • 永久存儲。內存掉電數據就沒了。

Q2:如果用了磁盤又會引入哪些問題?

  • 數據交互。磁盤&內存存儲的數據需要換入換出。
  • 誰來換。DB or OS,各自的實現方式以及優缺點。
  • 換哪些。LRU策略,內存刷入刷出的策略有哪些,各自的特點是啥?
  • 什麼時候換。刷髒頁的條件,髒頁線程輪詢;buffer pool滿了之類的。
  • 怎麼換。怎樣能有效的提高讀寫,鄰近頁怎麼處理,是否考慮順序的讀取、寫入。

Q3:誰來change page?

  • DB自身。同樣的page交換,OS天然就自帶這個功能mmap,爲啥不用呢?
  • 場景1:如果內存中沒有空間了,new page怎樣加進來?OS會care哪些是你經常用的page?不會,OS只會根據自己的策略去淘汰。DB失去了對數據的control。
  • 場景2:併發讀寫page,併發讀還好,如果是併發寫呢?DB該如何來保證隔離級別&高併發的性能

Q4:要知道數據怎樣在disk↔mem之間切換,先看看數據在disk上是怎樣存儲的

  • File → Page → Tuple
  • File。mysql8.0大多是情況下就是一個表一個idb文件
  • Page。可能包含tuples 元數據 索引 日誌ect;有一個唯一id,查找用。
    • 磁盤扇區 ~ 512字節,這個也是redo log寫盤的最小單位,保證原子性
    • OS ~ 4K
    • Mysql Page ~ 16K;因爲和OS的4K不對等,爲了保證原子,引入Double Write
  • Tuple。

Q5:File存儲

怎樣存儲page,文件中的page

  • linked list ❎
  • page dirctory ✅
    在這裏插入圖片描述

Q6:Page存儲

  • 存tuple(MySQL)
  • 存log(leveldb,rocksDB ) 分層→ 壓縮問題
    在這裏插入圖片描述

Q7:Tuple存儲

  • header。lsn信息[併發控制的],bitmap[NULL值信息]
  • data。字段值

Q8:PG怎樣找到對應的record

  • page_id+offset
# 通過citydi找到page_id + offset
postgres=# select ctid,* from r;
 ctid  | id  | val
-------+-----+-----
 (0,1) | 101 | aaa  ~~ page爲0的第一個記錄
 (0,2) | 102 | bbb 
 (0,3) | 103 | ccc

# 刪除是不會直接回收的
postgres=# delete from r where id=102;
DELETE 1
postgres=# select ctid,* from r;
 ctid  | id  | val
-------+-----+-----
 (0,1) | 101 | aaa
 (0,3) | 103 | ccc

# 插入新的數據會順延
postgres=# insert into r values(104,'ddd');
INSERT 0 1
postgres=# select ctid,* from r;
 ctid  | id  | val
-------+-----+-----
 (0,1) | 101 | aaa
 (0,3) | 103 | ccc
 (0,4) | 104 | ddd
(3 rows)

# 重整後數據會挪動
postgres=# vacuum full;
VACUUM
postgres=# select ctid,* from r;
 ctid  | id  | val
-------+-----+-----
 (0,1) | 101 | aaa
 (0,2) | 103 | ccc
 (0,3) | 104 | ddd

Q9:MySQL怎樣找到對應的record

# 8.0.20
# 根據表明找到TABLE_ID
mysql> select TABLE_ID,NAME from INNODB_TABLES where NAME='sbtest/sbtest1';
+----------+----------------+
| TABLE_ID | NAME           |
+----------+----------------+
|     1065 | sbtest/sbtest1 |
+----------+----------------+

# 根據主鍵找到root page
mysql> select INDEX_ID,NAME,TYPE,PAGE_NO,SPACE from INNODB_INDEXES where TABLE_ID=1065 and NAME='PRIMARY';
+----------+---------+------+---------+-------+
| INDEX_ID | NAME    | TYPE | PAGE_NO | SPACE |
+----------+---------+------+---------+-------+
|      151 | PRIMARY |    3 |       4 |     4 |
+----------+---------+------+---------+-------+

# 根據SPACE找到物理文件
mysql>  select * from INNODB_DATAFILES where SPACE=4;
+--------------+----------------------+
| SPACE        | PATH                 |
+--------------+----------------------+
| 0x34         | ./sbtest/sbtest1.ibd |
+--------------+----------------------+

# 二叉樹的根節點在 ./sbtest/sbtest1.ibd文件 + PAGE_NO[4]的位置
# 根據二叉樹找到對應的數據的page_id
# 然後在page中找滿足條件的slot
# 不同於pg,MySQL表中並沒有直接記錄record對應的pageid + offset信息

https://dev.mysql.com/doc/internals/en/innodb-page-directory.html
https://dev.mysql.com/doc/refman/8.0/en/innodb-information-schema-system-tables.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章