Mysql常见的存储引擎有什么,有什么区别
常见的存储引擎有MyISAM,InnoDB,MEMORY,MERGE.今天我们就分别介绍一下,
MyiSAM存储引擎特点
静态表的字段都是非变长字段,这样每个记录的长度是固定,这个方式的优点在于存储速度非常快,容易缓存,而且表发生损坏后也容易修复,缺点就是占空间.
包含变长字段,记录不是固定长度,优点就是占用空间少,但出错恢复起来很难修复
由myisampack工具常见,占据非常小的磁盘空间,因为每个记录是被单独压缩的,所以只有非常小的访问开支
InnoDB存储引擎
Memory存储引擎
Merge存储引擎
一般都如何设计索引
Mysql有那些分区类型,分别有什么作用
主要有4中分区类型
create tbale emp(
id int not null,
ename varchar(30),
hired date not null default '1970-01-01',
separated date not null default '1970-01-01',
job varchar(30) not null,
store_id int not null
)
partition by range(store_id)(
partition p0 values less than(10),
partition p1 values less than(20),
partition p2 values less than(30),
);
RANGE分区适用场景
create tbale expenses(
expense_date date not null ,
category int,
amount decimal(10,3) not null
)
partition by list(category)(
partition p0 values in(3,5),
partition p1 values in(1,10),
partition p2 values in(4,9),
);
LIST分区是建立离散的值列表告诉数据库特定的值属于那个分区,list分区是从属于一个枚举列表的值的集合
create tbale emp(
id int not null,
ename varchar(30),
hired date not null default '1970-01-01',
separated date not null default '1970-01-01',
job varchar(30) not null,
store_id int not null
)
partition by hash(store_id) partition 4
hash分区主要用来分散热点读,确保数据在预先确定个数的分区中尽可能的平均分布,hash分区分为两种,常规hash分区和线性hash分区,常规分区是取模算法,让数据平均分布在每个分区,提高查询效率,但是如果增加一个新的分区,原来的分区的数据就要重新计算,线性hash分区使用的是一个线性的2的幂的运算法则。当分区个数2的N次幂时,线性hash分区结果和常规hash分区结果是一致的,在分区维护时,Mysql能够处理的更加迅速,同时对比常规分区的时候,线性分区数据分布不太平衡。
语法上线性分区使用partition by linear hash(store_id) partition 4,
create tbale emp(
id int not null,
ename varchar(30),
hired date not null default '1970-01-01',
separated date not null default '1970-01-01',
job varchar(30) not null,
store_id int not null
)
partition by key (job) partition 4
类似hash分区但是hash分区允许使用用户自定义的表达式,而key分区允许使用用户自定义表达式,同时hash分区只支持整数分区,而ke分区支持使用除BLOB or text类型其他类型的列作为分区键,可以不用指定分区键,默认首先选择使用主键分区,如果没有主键的时候,会选择非空唯一键作为分区键(且唯一键是非空,否则也会报错)
一般是如何优化sql
通过show status了解各种sql的执行频率
可以用下面语句,了解当前数据库是更新和插入为主,还是以查询操作为主,以及各种类型的sql大致执行比例多少
定位执行效率低的sql语句
通过explain分析低效率sql的执行计划
table,数据结果的表
ALL<Index<range<ref<eq_ref<const,system<null
通过show profile分析sql
show profiles;
+----------+------------+-----------------------------+
| Query_ID | Duration | Query |
+----------+------------+-----------------------------+
| 1 | 0.00168250 | select count(*) from depart |
+----------+------------+-----------------------------+
1 row in set, 1 warning (0.00 sec)
show profile for query 1;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000605 |
| checking permissions | 0.000015 |
| Opening tables | 0.000023 |
| init | 0.000020 |
| System lock | 0.000477 |
| optimizing | 0.000019 |
| executing | 0.000196 |
| end | 0.000013 |
| query end | 0.000006 |
| closing tables | 0.000019 |
| freeing items | 0.000264 |
| cleaning up | 0.000028 |
+----------------------+----------+
12 rows in set, 1 warning (0.00 sec)
show profile cpu for query 1;
+----------------------+----------+----------+------------+
| Status | Duration | CPU_user | CPU_system |
+----------------------+----------+----------+------------+
| starting | 0.000605 | 0.000000 | 0.000000 |
| checking permissions | 0.000015 | 0.000000 | 0.000000 |
| Opening tables | 0.000023 | 0.000000 | 0.000000 |
| init | 0.000020 | 0.000000 | 0.000000 |
| System lock | 0.000477 | 0.000000 | 0.000000 |
| optimizing | 0.000019 | 0.000000 | 0.000000 |
| executing | 0.000196 | 0.000000 | 0.000000 |
| end | 0.000013 | 0.000000 | 0.000000 |
| query end | 0.000006 | 0.000000 | 0.000000 |
| closing tables | 0.000019 | 0.000000 | 0.000000 |
| freeing items | 0.000264 | 0.000000 | 0.000000 |
| cleaning up | 0.000028 | 0.000000 | 0.000000 |
+----------------------+----------+----------+------------+
12 rows in set, 1 warning (0.00 sec)
通过trace分析优化器如何选择执行计划
mysql支持目前支持那些索引
聚簇索引和非聚簇索引
聚簇索引,将数据存储和索引放到一起,索引结构的叶子节点保存了行数据
非聚簇索引,将数据与索引分开存储,索引结构的叶子节点指向数据对应的位置
在innodb中聚簇索引上创建的索引叫辅助索引,非聚簇索引都是辅助索引,像复合索引,前缀索引,唯一索引,辅助索引的叶子节点不是行的物理位置,而是主键值,辅助索引访问总要二次访问查找
聚簇索引具有唯一性,由于聚簇索引是将数据和索引结构放在一起,因此一个表仅有一个聚簇索引。
表中行的物理谁许和索引中的行的物理顺序是相同的,在创建任何非聚簇索引之前创建创建聚簇索引,这是因为聚簇索引改变表中行的物理顺序,数据行,按照一定的顺序排列,并且自动排序
聚簇索引默认是主键,如果没有主键会选择一个唯一非空的字段,如果还是没有就会自动定义一个主键作为聚簇索引
Myisam使用的非聚簇索引,非聚簇索引的两颗B+树看上去没有区别,节点结构完全一致,值存储的内容不同而已,主键索引节点存储的是主键,辅助索引存储的是辅助键,表数据存储独立的地方,这两颗b+树的叶子节点都使用一个地方指向真正的表数据,由于索引树是独立的,通过辅助索引无需在访问抓紧索引树
看上去聚簇索引的效率明显低于非聚簇索引,不用回表查询,那聚簇索引的优势是啥
为什么主键通常建议用自增id
聚簇索引的数据的物理存放顺序和索引顺序一直,只要索引相连的那么对应的数据一定也是相邻的,如果主键不是自增id,就会不断的调整物理地址,分页,如果是自增他只需要一页一页的写,索引结果紧促,磁盘碎片少,效率也高。
为什么B+树适合做索引
要知道这个问题的答案,首先我们必须先说一下二叉树查找树,平衡二叉树,红黑树,B树,以及最后的B+树各自的特点说明
二叉查找树:不平衡
也叫二叉排序树,任何节点的左子树所有的节点值都小于根节点,右子树所有的节点值都大于根节点,但是二叉查找树是不平衡
二叉树的查询时间取决于高度,平均时间复杂度是O(logN),但是有可能不断的添加至导致最终的不平衡,退化成链表如下
平衡二叉树(AVL):旋转耗时
由于二叉查找树的退化,引入了平衡二叉树,平衡二叉树左右子树高度差不能超过1,AVL查找,插入,删除在平均和最坏情况下都是O(logN)
但是由于平衡二叉树在插入和删除的时候,要破坏平衡二叉树,此时需要自旋重新平衡这个数,由于旋转的消耗,AVL树在删除数据的失效很低,在删除操作比较多的时候,维护平衡所需要的代价高于其他带来的好处,因此AVL实际使用并不高
红黑树,树太高
相比AVL树,红黑树并不是严格的平衡,只要确保从根到叶子的最长路径不多于最短可能路径的两倍长
由于红黑树的平衡性变差,所以查询的效率相对来说比较低,但是删除红黑树的删除效率大大提高,因为引入了颜色,当插入和删除的时候,只需要进行O(1)次数的宣战以及变色就能保证基本的平衡,不像AVL树进行O(longN)次旋转,总体来说性能高于平衡二叉树,但是对于数据在瓷片等辅助存储设备中的情况,红黑树并不擅长,因为红黑树长的还是太高了
B树,为磁盘而生
B树是为磁盘等辅助存储设备设计的多路平衡二叉树,而二叉树相比,B树每个非叶子节点可以有多个子树,因此当节点数量相同的时候,B树的高低比较的,是一个矮胖子,磁盘IO次数大大减少
B树除了树高度低,还有就是局部性原理,是指当一个数据被使用时候,其附件的数据有比较大的概率在短时间内被用到,B树是将临近的数据放到同一个节点,当访问某个数据的时候,会把整个节点放入缓存,以后直接可以从缓存中读取,无需进行磁盘I/O操作,命中率更高,
B+树
B+树叶是多路平衡查找树,但相比于B树的优点如下
但是B+树会出现键重复,因此占用更多的空间,但是总体而言带来的性能还是可以结束的,因此B+树更加广泛再使用.
Mysql使用索引的典型场景
索引失效有哪些场景
还有那些优化手段
analyze tbale tbl_name:用于分析和存储表的关键字分布,分析的结果将可以使得
系统得到准确的统计信息,使得sql能够生成正确的执行计划
check table tbl_name:检查一个或多个表是够有错误
optimize table tbl_name:如果已经删除了表的一部分,或者如果对含有可变长度
行的表进行了很多更改,则使用这个命令进行空间碎片进行合并
2.大批量插入数据
如果存储引擎是MyISAM引擎,可以使用下面语句
alter table tbl_name disable keys
loading data infile '文件路径' into table tbl_name
alter table tbl_name enable keys
如果是InnoDB存储引擎,可以使用下面方式
3.如果进行insert语句,可以使用下面方式
4.对于order by 优化
mysql有两种排序方式
filesort是通过响应的排序算法,将取的数据在sort_buffer_size系统变量设置的内存排序区进行排序,如果内存装载不下,可以将磁盘的数据进行分块,在对各个数据块进行排序,然后将各个块的数据进行合并有序的结果集,
所以我们可以知道我应该减少额外的排序,通过索引直接返回有序数据。
5.FileSort的优化
通过合适的索引能够减少filesort的出现,但是某些情况,条件限制不能让filesort消失,我们就得看看如何优化filesort.
Mysql有两种filesort排序算法
如何选择算法,是根据max_lenght_for_sort_data的大小和query语句去取出的字段总大小判断,如果max_lenght_for_sort_data大,使用第二种优化算法,否则使用第一种
因此我可以尽量吊打max_lenght_for_sort_data的值,让mysql选择更优化的filesort排序算法,也可以适当加大sort_buffer_size排序区,尽量在内存中排序完成,而不是通过临时表放在文件进行,也不能无限加大,会导致服务器SWAP严重,
优化嵌套查询
子查询就是把select语句创建一个单例查询结果,然后把结果作为过滤条件放到另外一个查询,一次性查询可以避免事务或表锁死,但是有时间使用join更有效率,因为join不需要在内存中创建临时表完成这个逻辑上两个步骤的查询,
优化分页查询
我们使用limit 1000,20,此时是把前1020条数据查询出来仅仅返回1001到1020条数据,抛弃了前1000条数据,是在浪费,因此有以下优化思路
在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容
(select film_id from film order by title limit 50,10)
把limit转换成某个位置的查询
mysql锁问题
锁类型 | 特点 |
---|---|
表级锁 | 开销小,加锁快,不会出现死锁,锁粒度大,锁冲突概率最高,并发率低 |
行级锁 | 开销大,加锁慢,会出现死锁,锁粒度小,锁冲突概率低,并发率高 |
页面锁 | 开销,加锁,以及锁冲突介于表级锁和行级锁之间,会出现死锁, |
表级锁
有两种模式,表共享读锁,表独占写锁,对于MyISAM的读操作,不会阻塞其他用户对同一个表读,但是会阻塞同一个表的写请求,对于MyISAM的写操作,会阻塞对同一个表的读写操作,MyiSAM的读操作和写操作之间,和写操作之间是串行的
由于MyiSAM是一次性给表加所有需要的锁,因此他不会出现死锁,
我们知道MyISAM的读写操作是串行的,同时我们要知道如果一个进程是读表,一个进程是写锁,他们同时对一个表操作,是如何执行的呢,其实MyISAM是先进行写操作,在进行读操作,即使读操作先到锁的等待队列,写请求后到,也会把写请求放到读请求之前,这是因为Mysql认为写操作比读操作重要,因此MyISAM不适合大量更新操作的和查询的操作,当然我们也可以修改参数进行优化,但是还是不建议使用在大量读写操作的场景使用MyISAM。
InnoDB锁问题
innoDB存储引擎和MyISAM存储引擎最大的不同,就是支持事务和行锁,事务具有的属性
原子性 | 事务是一个原子操作.要么全部执行,要么全部不执行 |
---|---|
一致性 | 事务开始和完成时,数据都必须保持一致性, |
持久性 | 事务完成之后,对数据的修改是永久性的 |
隔离性 | 保证事务在不受外部并发操作影响的独立环境执行 |
对于并发事务处理带来的问题
更新丢失 | 多个事物处理同一行数据,后执行的覆盖前一次执行的操作 |
---|---|
脏读 | 一个事物正在操作,未提交,但是另外一个事物对正在操作的事物读取且进一步处理,就会产生脏读 |
幻读 | 同样的条件搜索,两次搜索的结果不一样,第二次的查询中多了新的数据 |
不可重复读 | 对同一条数据的读取后,再次去读发现记录删除或者修改了 |
事物的隔离级别
数据库实现事物隔离的方式,基本可以分成两种
InnoDB的行锁模式
select * from tableName where .... lock share mode(共享锁)
select * from tableName where .... lock update(排他锁)
InnoDB行锁的实现方式
行锁是通过给索引加锁来实现的,如果没有索引,会在默认的聚簇索引上对记录加锁,分三种情况
注意的是如果不通过所以索引条件搜索数据,那么InnoDB将对表中的所有记录加锁,实际效果和表锁一样
实际应用中,要注意上面说的行锁的特点,否则导致大量的锁冲突
Next-key LOCK
对范围条件而不是相等条件检索数据,并请求共享或排他锁时候.InnoDB会对符合条件的记录加锁,对于记录符合条件但不存在的记录叫做间隙,对这种加锁,叫做间隙锁,比如我有101条记录,1,2,3...101,使用下面语句范围查询
select * from table where id>100 for update
不但会对101加锁也会对大于101的记录加间隙锁,间隙锁是为了防止幻读,比如如果其他事物对大于101的数据插入操作,就会产生幻读,其次是为了恢复和复制的需要,因此我们在使用范围查询的时候,可能会导致长时间等待,所以尽量使用等值查询,同时我们要记住对于一个不存在的记录使用等值条件,也是会加锁的,
什么时候使用表锁
如何避免死锁
两个事物需要获取对方持有的排他锁才能继续完成事物,就是循环导致的死锁
如何避免死锁常用方式
内存优化的原则
MyISAM内存优化
InnoDB内存优化
由于mysq的数据页(一般是16KN)和操作系统的IO数据页大小(一般是4KB)不一致,无法保证InnoDB缓存也被完整,一致的刷新到磁盘,比如当发生部分断裂时候,就会出现无法恢复的问题
因此引入了doublewrite的机制,用系统表空间的一块连续的空间(大小是2MB)作为doublewrite buffer,当进行脏页刷新的时候,首先把脏页的副本刷新到doublewrite buffer中,然后调用fsync调用操作系统缓存,确保副本完整的写入到磁盘,最后InnoDB后台线程将脏页刷新到磁盘数据文件中。
Mysql binlog unlog redolog作用和区别
redolog产生的背景就是,如果每一次数据的操作都写入磁盘中,首先磁盘先要找到对应的记录然后更新整个过程,查询的成本很高,所以为了提高mysql的性能,引入了类似酒馆黑板的方式,下班更细你数据放到某个地方,待空闲的时候写入磁盘中
redolog日志是物理日志,记录的是修改了什么,记录事物操作的变化,属于InnoDB存储引擎的,不管事物是否提交,都会被记录下来,这种先写日志后写磁盘的技术称之为WAL技术,即当一条数据更新的的时候.先会写入redo log即黑板上,并更新内存,这样就更新操作完成了,同时引擎会在闲暇的时候讲redo log的记录写入磁盘
redolog日志的记录是数据页的变更,而这种记录没有必要持久化,因此他是固定大小,循环写入,如下图
其中write pos 就是此时写入的位置,之前的位置就是写入记录的地方,而checekpoint 就是把记录刷新到磁盘的位置,之前的数据已经被刷新到磁盘了,当这两个位置相遇的时候,就会停止更新操作,转而进行redo log日志同步到磁盘,
redo log日志,那么数据库进行异常重启的时候,可以根据redo log 日志进行恢复,达到了crash-safe
binlog日志
binlog是mysql数据库service层,是所有存储引擎共享的日志模块,当事物commit提交的时候,以二进制的形式保存于磁盘中,binlog是逻辑日志是已追加的形式写入的
可以设置sync_binglog控制写入磁盘的时机
他有三种模式
binglog主要用再主从复制,和数据恢复场景中
undo log日志
undo log日志记录的是每条数据的所有版本,比如update语句,我会将该条记录的数据记录到undolog日志中,并且将最新版本你的roll_pointer指针指向上一个版本,这样就可以形成当前的所有版本,这就是mvcc机制,即用户读取一行记录时候,若该记录已经被其他事物占用,当前事务可以通过undo log读取之前的行版本信息,一实现非锁定读取。
undo log 记录的是逻辑日志,可以认为当delete一条记录的时候,undolog 记录的是insert记录,当update 语句的时候,记录的是一条相反的update记录
bingLog和redo log如何写入保证数据的一致性
update tb_name set c=c+1 where id =2
mysql使用了两阶段提交保证两份日志的逻辑一致,我们假设上面的update语句id=2,此时的c=0,再假设我们第一个日志成功,第二个日志失败,不使用两阶段提交,会发生什么情况,
因此我们需要使用两阶段提交保证两个日志保持一致。
磁盘IO调度算法
传统的硬盘读取数据分为三个步骤
磁盘上面的动作的快慢取决于访问时间和传输速度,也叫延迟和吞吐量
IO的请求处理快慢取决于磁盘的寻到时间,因此操作系统并不是每次IO都去寻道,而是进行合并和排序,合并就是把相邻的和同一个的请求进行和并,对于相邻扇区通过合并但是对于非相邻的扇区就可以进行排序处理,因为IO请求按照扇区增长排序,一次旋转就可以访问更多的扇区,更够缩短所有请求的实际寻道时间
Lunux也提供了四种调度算法