zoukankan      html  css  js  c++  java
  • MySQL的架构

    一、MySQL逻辑架构

    前言:为了充分发挥MySQL的性能并顺利地使用,就必须理解其设计

    MySQL最重要、最与众不同的特性是它的存储引擎架构,这种架构的设计将查询处理及其他系统任务和数据的存储/提取相分离。所以这种处理和存储分离的设计可以在使用时根据性能、特性,以及其他需求来选择数据存储的方式

    1、MySQL的逻辑架构图

    1.1、连接管理与安全性

    1.2、优化与执行

    2、并发控制

    2.1、读写锁

      共享锁(读锁)、排他锁(写锁)

    2.2、锁粒度

      表锁、行级锁

    3、事务

    3.1、 ACID

    3.2、隔离级别

      未提交读(脏读)  事务可以读取未提交的数据,性能不比其他级别好太多,如非必要一般不使用

      提交读(不可重复读)  一个事务从开始直到提交之前,所作的任何修改对其他事务都是不可见的  

      可重复读(MySQL的默认事务隔离级别)  解决了脏读问题,保证了在同一个事务中多次读取同样记录的结果是一致的。但可重复读会出现幻读问题,当一个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,这时当之前的事务再去读取该范围的记录时,就产生了幻行

      可串行化(最高隔离级别)  强制事务串行执行,避免了幻读的问题,在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别

    3.3、死锁

      死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象

      为了解决这种问题,数据库系统实现了各种死锁检测和死锁超时机制。InnoDB目前处理死锁的方式是,将持有最少行级排他锁的事务进行回滚

      锁的行为和顺序是和存储引擎相关的。死锁发生以后,只有部分或者完全回滚其中一个事务,才能打破死锁。所以应用程序在设计时必须考虑如何处理死锁,大多数情况下只需重新执行因死锁回滚的事务即可。

    3.4、事务日志

      事务日志可以帮助提高事务的效率。

      使用事务日志,存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为 记录到 持久在硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘。

      事务日志采用的是追加的方式,因此写日志的操作是磁盘上一小块区域内的顺序I/O,而不像随机I/O需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快得多

      在事务日志持久以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。通常称为预写式日志,所有其实修改数据需要写两次磁盘(一次是事务日志持久化到磁盘,一次是修改数据刷回到磁盘)

    3.5、MySQL中的事务

      MySQL提供了两种事务型的存储引擎:InnoDB和NDB Cluster。另外还有一些第三方存储引擎也支持事务,比较知名的包括XtraDB和PBXT

      MySQL默认采用自动提交模式。如果不是显式地开始一个事务,则每个查询都被当作一个事务执行提交操作。

    4、多版本并发控制

      MySQL的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)

      MVCC的实现,是通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长时间,每个事务看到的数据都是一致的。因为事实上根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的

      不同存储引擎的MVCC实现是不同的,典型的有乐观(optimistic)并发控制和悲观(pessimistic)并发控制。

      悲观锁的理解:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。悲观锁的实现,往往依靠底层提供的锁机制;悲观锁会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。

      乐观锁的理解:假设不会发生并发冲突,每次不加锁而是假设没有冲突而去完成某项操作,只在提交操作时检查是否违反数据完整性。缺点是不能解决脏读的问题,所以通常乐观锁与提交读的隔离等级共同使用。

      InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。这两个列,一个保存了行的创建时间,一个保存行的过期时间(或删除时间),实际上存储的不是实际的时间值,而是系统版本号。每开始一个新事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

      以可重复读(REPEATABLE READ)隔离级别为例,解析MVCC具体如何操作:

      SELECT

        InnoDB会根据以下两个条件检查每行记录:

        1、只查找版本早于当前事务版本的数据行(行的系统版本号小于或等于事务的系统版本号),确保事务读取的行,要么是在事务开始前已经存在,要么是事务自身插入或者修改过

        2、行的删除版本要么未定义,要么大于当前事务版本号,确保事务读取到的行,在事务开始之前未被删除。

        只有符合这两个条件的记录,才能返回作为查询结果

      INSERT

        为新插入的每一行保存当前系统版本号作为行版本号

      DELETE

        为删除的每一行保存当前系统版本号作为行删除标识

      UPDATE

        为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识

      优缺点:保存两个额外系统版本号,使大多数读操作都可以不用加锁。使读数据操作很简单,性能很好。不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作

      MVCC只在可重复读和提交读两个隔离级别下工作。因为未提交读总是读取最新的数据行,而不是符合当前事务版本的数据行。而可串行化则会对所有读取的行都加锁。

    5、MySQL的存储引擎

      在文件系统中,MySQL将每个数据库保存为数据目录下的一个子目录。创建表时,MySQL会在数据库子目录下创建一个和表同名的.frm文件保存表的定义。因为MySQL使用文件系统的目录和文件来保存数据库和表的定义,大小写敏感性和具体的平台密切相关。

      不同的存储引擎保存数据和索引的方式是不同的,但表的定义则是在MySQL服务层统一处理。

    5.1、InnoDB存储引擎

      InnoDB是MySQL的默认事务型引擎,也是最重要、使用最广泛的存储引擎。

      InnoDB的性能和自动崩溃恢复特性,使得它在非事务型存储的需求中也很流行。

      InnoDB的数据存储在表空间中,表空间是由InnoDB管理的一个黑盒子,由一系列的数据文件组成。

      InnoDB采用MVCC来支持高并发,并实现了四个标准的隔离等级。其默认级别是可重复读,并且通过间隙锁策略防止幻读的出现。间隙锁使得InnoDB不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻影行的插入。

      InnoDB表是基于聚簇索引建立的。聚簇索引对主键查询有很高的性能,不过它的二级索引(非主键索引)中必须包含主键列,所以如果主键列很大的话,其他的所有索引都会很大。因此,若表上的索引较多的话,主键应当尽可能的小。

      InnoDB内部做了很多优化,包括从磁盘读取数据时采用的可预测性预读,能够自动在内存中创建hash索引以加速读操作的自适应哈希索引,以及能够加速插入操作的插入缓冲区等。

      作为事务型的存储引擎,InnoDB通过一些机制和工具支持真正的热备份,MySQL的其他存储引擎不支持热备份。

     5.2、MyISAM存储引擎

      在MySQL 5.1及之前的版本,MyISAM是默认的存储引擎。提供大量的特性,包括全文索引、压缩、空间函数(GIS)等,但不支持事务和行级锁,一个毫无疑问的缺陷就是崩溃后无法安全恢复。

      MyISAM引擎设计简单,数据以紧密格式存储,所以在某些场景下的性能很好。但最典型的性能问题还是表锁问题,如果所有的查询都长期处于锁定状态,那么查询的速度无疑是很慢的。

    5.3、MySQL内建的其他存储引擎

      Archive引擎,是一个针对高速插入和压缩做了优化的简单引擎。只支持INSERT和SELECT操作,会缓存所有的写并利用zlib对插入的行进行压缩,所以比MyISAM表的磁盘I/O更少。每次SELECT查询都需要执行全表扫描,适合日志和数据采集类应用或者在一些需要更快速的INSERT操作的场合下使用。支持行级锁和专用的缓冲区,所以可以实现高并发的插入。

      CSV引擎,可以将普通的CSV文件(逗号分割值的文件)作为MySQL的表来处理,但不支持索引。将数据存储为CSV文件,然后复制到MySQL数据目录下,就能在MySQL中打开使用。将数据写入到一个CSV引擎表,其他外部程序也能从表的数据文件中读取CSV格式的数据。因此CSV引擎可以作为一种数据交换的机制,非常有用。

      Memory引擎,如果需要快速地访问数据,并且这些数据不会被修改,重启以后丢失也没有关系,那么使用Memory表是非常有用。比MyISAM表快一个数量级,因为数据保存在内存中,不需要进行磁盘I/O。Memory表的结构在重启以后还会保留,但数据会丢失。应用场景为用于查找或者映射表、缓存周期性聚合数据的结果、用于保存数据分析中产生的中间数据。支持Hash索引,因此查找操作非常快。是表级锁,因此并发写入性能较低。不支持BLOB或TEXT类型的列,并且每行的长度固定,即使指定VARCHAR列,实际存储也会转成CHAR,可能导致部分内存的浪费。如果MySQL在执行查询中需要使用临时表保存中间结果,内部使用的临时表就是Memory表。如果中间结果超出Memory表的限制,或者含有BLOB或TEXT字段,则临时表会转换成MyISAM表。

    5.4、第三方存储引擎

      OLTP类引擎

        XtraDB存储引擎是基于InnoDB引擎的一个改进版本,已经包含在Percona Server和MariaDB中,它的改进主要集中在性能、可测量性和操作灵活性方面。

      面向列的存储引擎

        MySQL默认是面向行的,每一行的数据是一起存储的,服务器的查询也是以行为单位处理的。而在大数据量处理时,面向列的方式可能效率更高。如果不需要整行的数据,可以传输更少的数据,如果每一行都单独存储,那么压缩的效率也会更高。

        Infobright是最有名的面向列的存储引擎,是为数据分析和数据仓库应用设计的。

    5.5、选择合适的引擎

    5.6、转换表的引擎

      将表的存储引擎转换成另外的一种引擎有很多方法,下面讲述其中的三种方法:

      1、ALTER TABLE

        ALTER TABLE mytable ENGINE = InnoDB;

        优点:可以适用任何存储引擎

        缺点:执行时间长,MySQL会按行将数据从原表复制到一张新的表中,期间可能会消耗系统所有的I/O能力,所以替代方案采用导出与导入,手工进行表的复制

        注意:如果转换表的存储引擎,将会失去和原引擎相关的所有特性。

      2、导出与导入

        使用工具将数据导出到文件,然后修改文件中CREATE TABLE 语句的存储引擎选项,注意同时修改表名。注意在CREATE TABLE 语句前的DROP TABLE语句,不注意可能会导致数据丢失。

      3、创建与查询(CREATE和SELECT)

        综合第一种的高效和第二种的安全,不需要导出整个表的数据,先创建一个新的存储引擎表,然后利用INSERT...SELECT语法来导数据:

        CREATE TABLE innodb_table LIKE myisam_table;

        ALTER TABLE innodb_table ENGINE=InnoDB;

        INSERT INTO innodb_table SELECT * FROM myisam_table;

        如果数据量不大,这样做工作得很好。如果数据量大,可以考虑分批处理,针对每一段数据执行事务提交操作。

        

        假设有主键字段id,重复运行以下语句(最小值x和最大值y进行相应的替换)将数据导入到新表:

        START TRANSACTION;

        INSERT INTO innodb_table SELECT * FROM myisam_table WHERE id BETWEEN x AND y;

        COMMIT;

        新表是原表的一个全量复制,原表还在。如果需要可以删除原表,如果有必要,可以在执行的过程中对原表加锁,以确保新表和原表的数据一致。

        

  • 相关阅读:
    Glide优化
    Java多线程知识点
    Android知识点
    Gradle的一些技巧和遇到的问题
    Python用Django写restful api接口
    Python写爬虫爬妹子
    用最简单的例子说明设计模式(三)之责任链、建造者、适配器、代理模式、享元模式
    【Python】扫描指定文件夹下特定后缀的文件
    【Python】生成多级树结构的xml文件
    【转】【Linux】安装pyinstaller
  • 原文地址:https://www.cnblogs.com/chjxbt/p/10477961.html
Copyright © 2011-2022 走看看