关系型数据库

Posted on 2023年11月15日周三 技术

存储结构

Hash 索引

SSTable

  1. 当写入时,将其添加到内存中的平衡数据结构中(例如红黑树)。
  2. 当内存大于某个阈值(通常为几兆字节)时,将其作为SSTable文件写入磁盘。
  3. 为了处理读请求,首先尝试在内存表中查找键,然后是最新的磁盘段文件,接下来是次新的磁盘段文件,以此类推,直到找到目标(或为空)。
  4. 后台进程周期性地执行段合并与压缩过程,以合并多个段文件,并丢弃那些已被覆盖或删除的值。

B-tree

B+ 树和 B 树的区别:B+ 树把所有数据都存储在叶节点中,而 B 树在非叶子结点也会存储数据。

InnoDB 使用的是 B+ 树,因为 B+ 树对范围查询更高效。

InnoDB 使用 B+ 树:

跳表

InnoDB

MySQL一个table中数据在磁盘上的排列是以clustered index为序的,在没有特殊设置的情况下,clustered index为primary key,如果没有primary key,就会找第一个不允许空值的unique key作为clustered index,还没有的话,db会自己生成一个index。

索引

一些逻辑上的索引

MVCC

每行记录包含了两个隐藏字段,事务id trx_id 和回滚指针 roll_pointer。

其中回滚指针指向对应undo log的地址,undo log在每次变动前被创建,相关的记录连在一起就变成了一个版本链。

如果一个事务不应该读取当前的版本,那么这个事务就会通过roll_pointer找到之前的版本。

Index Merge

当一个查询涉及多个索引的时候,优化器会在这两种策略中选择一种去执行

此时多个索引都会加入到锁机制中,很有可能不同类型的索引对应的区间有交叉,这就会带来死锁。

binlog

https://dev.mysql.com/doc/internals/en/binary-log-overview.html

有关数据修改的操作记录,记录了有可能导致数据更新的操作,以及一些相关的metadata。

两种实现方式:

用于:

redo log

如果每次事务结束的时候都要去把数据写入磁盘,会非常耗时,而且InnoDB修改的是页,等于是把页块随机IO进磁盘。因此引入了redo log,修改数据前先把修改的具体数据信息追加到log尾部,以减少数据页写入磁盘的频次。

redo log是环形的,一旦写满就要求数据页写入磁盘,然后释放相应的log空间。

如果发生了故障,redo log可以用来追加未写入磁盘的改动。

undo log

https://dev.mysql.com/doc/refman/8.0/en/innodb-undo-logs.html

记录用来回滚事务需要的信息,MVCC的版本信息也依赖此实现。

事务的级别

MySQL

为什么选择 MySQL?因为这是个万金油数据库,方便系统迁移,方便私有化部署等。

基础规范

  1. 一般场景下尽量使用InnoDB存储引擎。
  2. 新库字符集选择上使用utf8mb4字符集。
  3. 线上数据库禁止使用存储过程、视图、触发器、Event,在高并发的场景下我们需要去解放DB的CPU,把一些可以上移的计算上移。

使用规范

  1. 不要使用负向查询(不等于、not in、not like等)以及%开头的模糊查询;这些都会导致索引失效。
  2. 不要在WHERE条件的字段上直接使用函数或者表达式;比如 from_unixtime(start_day) > '...' 这样也会导致索引失效。
  3. 不要在WHERE条件的字段使用隐式转换;比如用int value去查询varchar的属性,这也会导致全表扫描。
  4. 最好不要SELETE *,只获取必要的字段,显示说明列属性。
    1. 这会增加CPU、IO、net消耗。
    2. 如果有覆盖索引的情况下,会导致无法有效利用覆盖索引。
    3. 可能会让字段的改变引发bug。
  5. 分片库使用场景下,要求在线查询必须带分片键。

优化思路