事务隔离级别、锁、索引、存储引擎
1.隔离级别
1.1未提交读(read uncommit) RU
这是最低级别的隔离等级:
在这种隔离级别下,可以读取未提交的事务修改/更新到的数据,基本无数据库会选择该隔离级别
事务一
select * from 表A where id = 1 读取到 name = 张三
事务二
update 表A set name = "李四" where id = 2
事务一
select * from 表A where id = 1 读取到 name = 李四
(然后事务二被回滚)
数据库里为"张三",但是读取为李四,所以为"脏"读
左边是事务1,先查一次,查到id为1的数据name为张三,这时候事务2又来了,把张三改成了李四,然后事务1又进行了一次查询,查出来了name为李四,那么假如这时候事务2发生了回滚,也就是name还是张三,但是事务1却读到了李四,这就是脏读。
1.2已提交读(read commit) RC
oracle和mysql的默认隔离级别:
在已提交读的情况下,虽然未提交的事务数据不会读取到,但是在这种情况下,会由于事务的执行也是需要时间的,在一个事务的两次相同查询间隔期间,存在其他事务提交,对数据库的数据进行了删除或者插入,那么这一个事务的两次查询结果就不一致了,这就是不可重复读。
1.2.1如何避免不可重复读:
mysql:
这里必须提到mysql的并发控制策略(锁策略)——共享锁和排他锁,见另一标题(mysql锁介绍)。
基于MyISAM引擎表在执行查询前,会自动执行表的加锁、解锁操作,一般情况下不需要用户手动加、解锁,但是有的时候也需要显式加锁,例如上文中存在的同一个事务中的两次关联紧密查询。
形如:
lock tables ynst_fgfc_sum_app_dq_rlt_anls read,ynst_fgfc_count read;
select * from ynst_fgfc_sum_app_dq_rlt_anls;
select * from ynst_fgfc_count;
unlock tables;
1.3可重复读(repeatable read) RR
该情况解决了不可重复读的问题,但是存在幻读的问题,也就是在一个事务的两次查询过程中,存在更新和删除语句,查询出来的记录存在误差,给人一种幻觉,说起来和不可重复读基本一致,但是不可重复读针对的是数据库的更新和删除操作,幻读针对的是插入操作。
1.3.1串行化serializable
最高级别隔离,所有的事务都是顺序执行的,不存在并行的情况,所以也就不会出现脏读,幻读和不可重复读,但是这样肯定是降低了数据库执行效率的。
1.3.2事务隔离实现方案
LBCC
适用于读多写少的使用场景,在事务执行时锁定所有关联资源,读取时给数据加上共享锁,不允许其他事务给数据加上排他锁,写入时给数据加上排他锁,不允许其他任何锁的添加,执行完成之后进行锁的释放。
MVCC
适用于写多读少的使用场景,引用涉及到了快照的概念,大致理念是在事务的第一次查询是通过数据库innodb引擎内部给表添加的DB_TRX_ID(事务id)字段和DB_ROLL_PTR(回滚指针)给数据添加快照,其他事务改变数据时会给这两个字段进行填充,涉及到的事务通过这两个字段的填充值在解析sql时添加条件从而达到事务涉及数据不变的效果。
2.mysql锁介绍
锁的开销是较为昂贵的,锁策略其实就是保证了线程安全的同时获取最大的性能之间的平衡策略。
共享锁:
共享锁又称读锁,即多个连接可以共享读取同一条数据,但仅限于读取时使用,在没有排他锁加在资源上时,读锁是可以协调所有资源的,读锁之间不互相阻塞。
排他锁:
排他锁又称写锁,即当进行写入操作时,将当前表/当前行数据进行锁定,阻止其他的事务对表/行进行写入/读取,注意排他锁会阻塞所有相关的事务对数据的写入和读取,所以优先级是高于读锁的。这里有两个策略,一个是表锁,一个是行锁,mysql的基本锁策略默认使用的表锁:
-
表锁,顾名思义,锁住当前整个表,开销最小。
-
行锁,锁住当前事务所设计的表,一般是在存储引擎底层使用,开销最大。
(这里的开销指的是系统对锁的管理,如果系统分配太多资源管理锁,自然会导致性能下降)
2.1锁使用场景
以一个sql举例:
update from 表A set columnA = "张三" where columnB = 1;
如果columnA存在索引,查询时会对匹配行进行锁定,不存在索引时进行锁表。
上面的太简单了:
实际上如何分析加锁,首先应该了解三点:
-
隔离级别(上面有提到)
-
索引和执行计划https://www.jianshu.com/p/7a0c215edb1d
-
sql中字段是否含有索引
2.1.1锁使用情况查询
select * from information_schema.innodb_locks
查看数据库锁的使用情况(innodb引擎)
select * from information_schema.innodb_lock_waits
索引类型
普通索引,查询时会用到的,并不要求唯一性的常用索引
create index ynst_fgfc_sum_app_dq_rlt_anls_DAY_FG_CNT_uindex
on ynst_fgfc_sum_app_dq_rlt_anls (DAY_FG_CNT);
唯一索引(关键字unique),要求涉及到的列/组合列唯一,可以包含空值,和主键不一样,主键是唯一索引加上字段不为空限制。
create unique index ynst_fgfc_sum_app_dq_rlt_anls_DAY_FG_CNT_uindex
on ynst_fgfc_sum_app_dq_rlt_anls (DAY_FG_CNT);
全文索引(关键字FULLTEXT),在mysql3.2版本加入,但是在mysql5.7.6才支持中文全文索引,只能在VARCHER,VACHER2,TEXT类型的字段上加索引。
添加索引:
alter table ynst_fgfc_sum_app_dq_rlt_anls add fulltext testIndex(PRO_CODE);
直接创建索引:
create fulltest index on ynst_fgfc_sum_app_dq_rlt_anls (PRO_CODE)
注意: 1:先导入数据再创建全文索引比后导入数据再创建索引要快很多
目前全文索引值支持MyISAM和InnoDB两种存储引擎
索引的作用是为了加快查询速度,所以在使用索引优化数据库的同时
一方面是需要让sql命中索引(暂放)
一方面也需要明确索引的使用场景,给表加上索引会降低数据的更新速度,执行更新操作之后数据库需要对索引文件进行保存操作,数据量过大会带来时间上的损耗,索引文件一般不会很大,但是在大数据量+组合列索引的情况下会比较严重,它会大幅占用磁盘空间。
4.存储引擎
数据库默认的存储引擎是InnoDb
除此之外还有MyISAM存储引擎
MEMORY存储引擎(瞬态,非重要的数据,数据服务重启后丢失)
MERGE存储引擎
CSV存储引擎
InnoDB与MyISAM最大不同有两点:
- 支持事务
- 采用行级锁
具体见官网说明
https://dev.mysql.com/doc/refman/5.7/en/myisam-storage-engine.html
查询资料:
- 深入分析MySQL中事务以及MVCC的实现原理
https://baijiahao.baidu.com/s?id=1669272579360136533&wfr=spider&for=pc
- mysql索引总结
https://www.jianshu.com/p/7a0c215edb1d
- 深入理解mysql——锁、事务和并发控制
https://zhuanlan.zhihu.com/p/36060546
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341