美文网首页
Mysql 存储引擎

Mysql 存储引擎

作者: 黄靠谱 | 来源:发表于2019-01-20 13:01 被阅读53次

    参考

    Mysql官网解释 5.6版本,存储引擎的详细介绍
    https://dev.mysql.com/doc/refman/5.6/en/myisam-storage-engine.html

    概述

    Mysql支持常用的4种存储引擎:Myisam、InnoDB(默认)、Memory、Merge

    • Myisam:高效缓存 多读少写时读取更快,B+树索引
    • InnoDB:支持事务、行级锁、外键,B+树索引
    • Memory:基于Hash索引,内存存储
    • Merge:分表时子表必须是Myisam

    SHOW ENGINES;查看,Mysql支持多种存储引擎。

    MyISAM

    1. 特点
    • 在 heave-read的业务场景下,访问速度快
    • 主索引和辅助索引一样,都是非聚簇索引,数据和索引分离,存储的value值是真实数据的物理地址
    • 默认保存了表的总行数,select Count(*) 直接返回结果
    • 表锁,没有行锁,所以无法支持并发的写,比如无法支持同时修改一张表中2个不同的数据
    • Merge引擎分表时,子表必须是Myisam
    1. 使用场景:多读少写,不需要事务、外键,也不容易服务器异常的场景

    2. Myisam缓存机制
      每次通过索引读取数据的时候,Mysql都会缓存 这个 IndexPage 到内存当中,这个内存块的大小由 key_buffer_size(默认 8M)决定,记录了这个索引块里面的所有数据对应的物理地址信息,并且mysql有一个LRU队列去管理这个缓存块。
      包括修改的时候,也是直接修改这个缓存块(同时会记录日志),并且标记这个page为dirty,当从LRU队列里面移除的时候,如果Dirty则需要写回到硬盘上。
      因为缓存的只是索引和物理存储地址,而不缓存真正的数据,所以和Innodb相比,相同大小的缓存空间,Myisam可以缓存更多的索引。

    When read, a MyISAM table's indexes can be read once from the .MYI file and loaded in the MyISAM Key Cache (as sized by key_buffer_size).
    
    1. 5.7版本之后 Myisam不支持分区功能,只有InnoDB和NDB支持分区

    InnoDB

    • 支持事务:通过内部MVCC机制实现
    • 支持外键
    • 支持行级锁:行锁是建立在索引的基础之上的,行锁锁的是索引,不是数据,所以提高并发写的能力要在查询字段添加索引,否则用的还是表锁
    • 支持并发读写,因为索引查询是行锁
    • 自动增长列
    • 辅助索引是以非聚簇索引实现的,辅助索引的value存的是主键,所以主键越小越好,减小辅助索引树的大小
    • InnoDB is typically said to have better crash recovery,灾难恢复更稳定

    为什么Myisam比Innodb读取更快?

    结论:在多读少写的业务场景下,Myisam的read的速度快好几倍。但是在有读有写或者多读少写的业务场景下,Myisam因为是表锁会阻塞,读和写都慢。

    1. 非聚簇索引一次lookup:在非主键索引的Query的业务场景下,Myisam只需要一次B+树 key lookup,就可以读取到data的物理地址,再一次IO读取,就可以获取到磁盘的数据信息,但是 InnoDB却需要2次索引树查找,这个都是不在一个物理page的查找,所以Myisam理论上在这一点设计上差不多快一倍。

    2. Myisam没有MVCC,在任意时间节点,一个数据就只有1个值,而Innodb就可能同时存在多个版本,加大了搜索筛选条件。

    3. Myisam可以更好的利用缓存:因为索引和数据是分离的,只缓存索引(索引值里面有key值和dataAddress),然后再一次IO读取,就可以捞取到数据。
      但是Innodb因为数据和索引是存在一起的,必须同时缓存相应的索引和数据,所以相同缓存空间下,InnoDB可以缓存的数据量更少,缓存的命中率更低,但是一旦命中,则无需IO操作,可以直接返回数据。

    Myisam PK Innodb

    1. Innodb优势: 事务、外键、行级锁、并发读写、灾难恢复更靠谱
    2. Myisam优势: 文本索引、count(*)存储、多读少写时快速读取和高效缓存、表数据可以拷贝迁移

    数据存储结构

    数据存储位置: 在 %datadir%/databaseName
    默认一个page的大小是16k

    1. Myisam
      Myisam的存储结构: 索引和数据是分开存储的。
    • student.frm :存储表结构等相关信息
    • student.MYI:存储表的索引数据
    • student.MYD:存储表的具体数据

    Myisam的存储结构比较独立,可以通过直接拷贝这3个文件,来实现表数据的 跨库迁移,甚至可以是跨操作系统的迁移

    1. InnoDB
      InnoDB的存储结构:分为两种模式(共享模式和 默认的独占模式 innodb_file_per_table)
    • student.frm :存储表结构等相关信息
    • student.ibd :存储表全部的数据内容和索引内容

    共享表空间以及独占表空间都是针对数据的从物理意义上来讲:

    • 共享表空间: 会把表集中存储在一个系统表空间里。即每一个数据库的所有表的数据,索引文件全部放在一个文件中。该文件目录默认的是服务器的数据目录。 默认的文件名为:ibdata1 初始化为10M。
    • 独占表空间: 每一个表分别创建一个表空间,这时。在对应的数据库目录里每一个表都有.ibd文件(这个文件包括了单独一个表的数据内容以及索引内容)

    memory

    • 内存存储,mysql重启数据消失
    • 默认索引Hash算法,速度快,但是范围查找就慢,也可以通过指定 B+树为索引
    • 不支持事务、一般被redis memcache取代

    merge

    用来做分表用的,多个结构相同的表,虚拟出一个merge表,可单独取操作子表来实现高性能,通知也支持操作merge表来实现,逻辑上统一的数据。

    注意事项

    1. InnoDB只有在走索引查询加锁时才是行锁,否则都是表锁
      例如User表 主键 id,但是name字段没有索引,事务A 通过非索引字段 name来查询 huangzs的用户,并且锁定该数据(可能有多个 huangzs用户),因为name字段没有索引,所以是表锁
      在没有commit之前,开启事务B,尝试修改 name='huang'的操作是不能执行的,因为当前表被锁住了
    TXA:
    begin;
    update user set memo ='hzs' where name='huangzs'
    
    TXB:
    begin;
    update user set memo ='hzs' where name='huang'
    

    行级锁的正确使用:查询条件是通过主键字段进行行级锁的,所以可以并发的修改数据

    TXA:
    begin;
    update user set memo ='hzs' where id=500;
    
    TXB:
    begin;
    update user set memo ='hzs' where id=501;
    
    1. select的时候,只有 lock in share mode 或者 for update 才会锁定数据,没有限定词的话,默认是直接读取的,不存在竞争。也就是一行数据即使加锁了,直接select也可以查的到

    2. InnoDB死锁了也不用怕,去倒杯水就好了:mysql 默认有innodb_lock_wait_timeout:50s的设置,超过50s会自动释放锁

    如果你觉得对你有帮助的话,就给我点赞吧!

    相关文章

      网友评论

          本文标题:Mysql 存储引擎

          本文链接:https://www.haomeiwen.com/subject/icsxjqtx.html