数据库原理系列一:存储引擎(上)

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

猜你喜欢

转载自www.cnblogs.com/Alpes/p/13187033.html