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