MySQL技术内幕——读书笔记

目录

MySQL技术内幕——读书笔记

MySQL体系结构和存储引擎

定义数据库和实例

  • 数据库:物理操作系统文件或者其他形式文件类型的结合。在MYSQL数据库中,数据库文件可以是frm、MYD、MYI、ibd结尾的文件。当使用NDB引擎时,数据库的文件可能不是操作系统上的文件,而是存放在内存之中的文件,但是定义仍然不变。
  • 实例:MYSQL数据库由后台线程以及一个共享内存区组成。共享内存可以被运行的后台线程所共享。需要牢记的是,数据库实例才是真正用于操作数据库文件的。

​ MYSQL被设计为一个单进程多线程架构的数据库。

# 可以查看当MYSQL数据库实例启动时,会在哪些位置查找配置文件。
mysql --help | grep my.cnf

​ 在配置文件中有一个参数是datadir,改参数指定了数据库所在的路径。在LINUX操作系统下默认是/user/local/mysql/data,这个默认路径只是一个链接,实际指向/opt/mysql_data。所以用户必须保证/opt/mysql_data的用户和权限

MYSQL体系结构

​ MYSQL由一下几部分组成:

  • 连接池组件
  • 管理服务和工具组件
  • SQL接口组件
  • 查询分析器组件
  • 优化器组件
  • 缓冲组件
  • 插件式储存引擎
  • 物理文件

需要特别注意的是:存储引擎是基于表的,而不是数据库。

MYSQL存储引擎

​ 存储引擎是MYSQL区别与其他数据库的一个最重要特性。用户可以根据MYSQL预定一点额存储引擎接口编写自己的存储引擎。若用户对某一种存储引擎的性能或功能不满意。可以通过修改源码来得到想要的特性,这就是开源带给我们的方便与力量。

InnoDB存储引擎

  • 支持事务:主要面向在线事务处理(OLTP)应用。特点是
    • 行锁设计
    • 支持外键
    • 支持类似于Oracle的非锁定读,即默认读取操作不会产生锁。
  • 数据放在一个逻辑的表空间,这个表空间像黑盒一样由INNODB存储引擎自身进行管理。它可以将每个INNODB存储引擎的表单独存放到一个独立的ibd文件中。
  • 通过使用多版本并发控制(MVCC)来获得高并发性
  • 实现了SQL标准的四种隔离级别。默认为REPEATABLE级别。使用一种被称为next-keylocking的策略来避免幻读现象的产生。
  • 提供插入缓冲、二次写、自适应哈希索引、预读等高性能和高可用功能。
  • 表中数据采用聚集的方式存放,因此每场表的储存都是按主键的顺序进行存放,如果没有显式指定主键,则会为每一行生成一个6字节的ROWID,并作为主键。

MyISAM存储引擎

  • 不支持事务,支持全文索引,主要面向一些OLAP数据库应用。
  • 缓冲池只缓冲索引文件,不缓冲数据文件。
  • MYD用来存放数据文件,MYI用来存放索引文件。

NDB存储引擎

  • 集群架构:share nothing
  • 数据全部放在内存中,因此主键查找的速度极快,并且通过添加NDB数据存储节点可以线性地提高数据库性能,是高可用、高性能的集群系统。
  • NDB存储引擎的连接操作是在MYSQL数据库层完成的,而是在存储引擎层完成的。这意味着,复杂的连接操作需要巨大的网络开销

Memory存储引擎

  • 数据都存放在内存中,非常适合用于存储临时数据的临时表,以及数据仓库中的维度表。
  • 默认使用哈希索引
  • 只支持表锁,并发性能较差,不支持TEXT和BLOB列类型
  • 存储变长字段(varchar)时按照定常字段(char)的方式进行的,会浪费内存。

Archive存储引擎

  • 只支持INSERT和SELECT操作
  • 支持索引
  • 使用zlib算法将数据行进行压缩后存储,压缩比一般达1:10
  • 适合存储归档数据,例如日志信息等。
  • 使用行锁实现高并发的插入操作
  • 不支持事务

FEDERATED存储引擎

  • 不存放数据,只是指向一台远程MYSQL数据库服务器上的表。这非常类似于SQL SERVER的联结服务器和Oracle的透明网关
  • 不支持异构

Maria存储引擎

  • 支持魂村数据和索引文件
  • 行锁设计,提供了MVCC功能
  • 支持事务和非事务安全的选项
  • 更好的BLOB字符类型的处理性能。
# 查看数据库锁支持的存储引擎
SHOW ENGINES\G

InnoDB存储引擎

InnoDB存储架构


​ InnoDB存储引擎有多个内存块,可以认为这些内存块组成了一个大的内存池,负责如下工作:

  • 维护所有进程/线程需要访问的多个内部数据结构
  • 缓存磁盘上的数据,方便快速的读取,同时在对磁盘文件的数据修改之前在这里缓存。
  • 重做日志(redo log)缓冲

​ 后台线程的主要作用

  • 刷新内存池中的数据,保证缓冲池中的内存缓存是最新的数据
  • 将已经修改的数据文件刷新到磁盘文件,同时保障在数据库发生异常的情况下InnoDB能恢复到正常运行状态。

后台线程

  1. Master Thread

    ​ 核心线程,主要负责将缓冲池中的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新,合并插入缓冲,UNDO页的回收等。

  2. IO Thread

    • 在INNODB存储引擎中大量使用了AIO(Async IO)来处理写IO请求,这样可以极大提高数据库的性能。
    • 有四种IO Thread 分别是(1.0.x开始):
      • wrtie thread:4个
      • read thread:4个
      • insert buffer thread:1个
      • buffer log IO:1个
    • 可以使用innodb_read_io_threads 和 innodb_write_io_threads参数进行设置。
    • 读线程一定小于写线程
# INNODB版本查询
SHOW VARIABLES LIKE 'INNODB_VERSION'\G;

# INNODB THREAD 数量查询
SHOW VARIABLES LIKE 'innodb_%io_threads'\G;

# 查询IO THREAD
SHOW ENGINE INNODB STATUS\G;
  1. Purge Thread

    ​ 事务被提交后,其所使用的undolog可能不再需要,因此需要PurgeThread来回收已经使用并分配的undo页。从INNODB 1.1版本开始,可以将purge操作从MASTER THREAD中抽离出来,来减轻MASTER THEAD的工作。使用配置开始

    [mysqld]
    innodb_purge_threads=1

    ​ 从INNODB 1.2版本开始,可以支持多个purge Thread,这样做的目的是为了进行加快undo页的回收。例如可以设置4个

    SELECT VERSION() \G;
    SHOW VARIABLES LIKE 'innodb_purge_threads'\G;
  2. Page Cleaner Thread

    ​ 是在INNODB 1.2.x版本中引入的。起作用是将之前版本中脏页的刷新操作都放入到单独的线程中来完成。其目的是为简称MASTER THREAD的工作以及对用于查询线程的堵塞,进一步提高性能。

内存

  1. 缓冲池

    ​ InnoDB存储引擎是在磁盘按照页的方式进行管理,是基于磁盘的数据库系统。需要使用缓冲池技术提高数据库的整体性能。

    ​ 缓冲池就是一块内存区域,读取先再缓存找,找不到去磁盘加载。写入的是后续通过Checkpoint的机制刷新回磁盘。

SHOW VARIABLES LIKE 'innodb_buffer_pool_size'\G;

​ INNODB中缓存的数据

​ 从1.0.X版本开始,允许有多个缓冲池实例。每个页根据哈希值平均分配到不同缓冲池实例中。好处是减少数据库内部的资源竞争,增加数据库的并发处理能力。

## 查询缓冲池信息、状态
SHOW VARIABLES LIKE 'innodb_buffer_pool_instances'\G;

SHOW ENGINE INNODB STATUS\G;

SELECT POOL_ID, POOL_SIZE, FREE_BUFFERS, DATABASES_PAGES
FROM INNODB_BUFFER_POOL_STATUS\G;
  1. LRU List、Free List(空闲页列表) 和 Flush List(脏页列表)

    ​ InnoDB存储引擎使用LRU算法进行内存管理,不同的是,他最新读取的页不是放在列表的首部,而是放在midpoint的位置。midpoint位置可由参数innodb_old_blocks_pct控制,例如

    SHOW VARIABLES LIKE 'innodb_old_blocks_pct'\G;

    ​ 为什么不是用最基础的LRU算法呢?这是因为某些SQL(例如索林或者数据的扫描操作)可能会将缓冲池中的页被刷新出,影响缓冲池的效率。但是这类SQL的数据使用的页并不是活跃数据。

    ​ 为了更进一步优化这个问题,引入一个新的参数innodb_old_blocks_time,表示页读取到mid位置后需要等待多久才会被加入到LRU列表的热端。所以在执行上述类型的SQL时候,可以先设置这个参数保证原来的LRU列表热点数据不被刷出。

    SET GLOBAL innodb_old_blocks_time = 1000;
    
    # 一些操作
    .....
    
    SET GLOBAL innodb_old_blocks_time = 0;

    ​ 如果用户预估自己热点数据不止63%,可以在执行SQL前改变innodb_old_blocks_pct参数

    SET GLOBAL innodb_old_blocks_pct=20;
    • 数据库刚启动时,LRU列表是空的,即没有任何的页。所有页都放在Free列表中。
    • 当需要从缓冲池分页时,首先从Free列表中查找是否有可用的空闲页,若有则将该页从Free列表中删除,放入到LRU列表中。
    • 页从LRU列表的old部分加入到new部分时,称此时发生的操作为page made young
    • 因为innodb_old_blocks_time的设置而导致页没有从old部分移动到new部分的操作称为page not made young。
    • 通过命令SHOW ENGINE INNODB STATUS观察LRU列表以及FREE列表的使用情况和运行状态。
    SHOW ENGINE INNODB STATUS\G;

猜你喜欢

转载自www.cnblogs.com/BlueMountain-HaggenDazs/p/9288155.html