Mysql 存储引擎

2019-01-20  本文已影响53人  黄靠谱

参考

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

概述

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

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

MyISAM

  1. 特点
  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

为什么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的存储结构: 索引和数据是分开存储的。

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

  1. InnoDB
    InnoDB的存储结构:分为两种模式(共享模式和 默认的独占模式 innodb_file_per_table)

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

memory

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会自动释放锁

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

上一篇下一篇

猜你喜欢

热点阅读