事务4大特性,一致性具体指什么?这4个特性mysql如何保证实现的?
事务的四大特性
原子性:事务由一系列动作组成,整个事务的所有操作,要么全部完成,要么全部不完成
一致性:一旦事务完成,在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏
隔离性:隔离状态执行事务,事务与事务之间互不影响各自的操作和执行
持久性:在事务完成以后,该事务对数据库所作的更改操作便持久的保存在数据库之中,而不是临时的,也不会回滚
Mysql怎么保证一致性的?
从数据库层面,数据库通过原子性、隔离性、持久性来保证一致性。也就是说ACID四大特性之中,C(一致性)是目的,A(原子性)、I(隔离性)、D(持久性)是手段,是为了保证一致性,数据库提供的手段。数据库必须要实现AID三大特性,才有可能实现一致性。例如,原子性无法保证,显然一致性也无法保证。
但是,如果你在事务里故意写出违反约束的代码,一致性还是无法保证的。例如,你在转账的例子中,你的代码里故意不给B账户加钱,那一致性还是无法保证。因此,还必须从应用层角度考虑。
从应用层面,通过代码判断数据库数据是否有效,然后决定回滚还是提交数据!
Mysql怎么保证原子性的?
是利用Innodb的undo log。 undo log名为回滚日志,是实现原子性的关键,当事务回滚时能够撤销所有已经成功执行的sql语句,他需要记录你要回滚的相应日志信息
Mysql怎么保证持久性的?
是利用Innodb的redo log。
采用redo log的好处? 其实好处就是将redo log进行刷盘比对数据页刷盘效率高,具体表现如下
redo log体积小,毕竟只记录了哪一页修改了啥,因此体积小,刷盘快。
redo log是一直往末尾进行追加,属于顺序IO。效率显然比随机IO来的快。
Mysql怎么保证隔离性的?
利用的是锁和MVCC机制。
MVCC,即多版本并发控制(Multi Version Concurrency Control),一个行记录数据有多个版本对快照数据,这些快照数据在undo log中。
如果一个事务读取的行正在做DELELE或者UPDATE操作,读取操作不会等行上的锁释放,而是读取该行的快照版本。
在事务隔离级别为读已提交(Read Commited)时,一个事务能够读到另一个事务已经提交的数据,是不满足隔离性的。但是当事务隔离级别为可重复读(Repeateable Read)中,是满足隔离性的。
事务隔离级别,4个隔离级别分别有什么并发问题?
未提交读:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
已提交读:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
可重复读:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
串行化:最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
Mysql默认隔离级别?如何保证并发安全?
MySql默认采用可重复读
MySql存储引擎使用的InnoDB,InnoDB支持行级锁和表级锁,默认使用的是行级锁,InnoDB的行级锁有两种:
共享锁:只允许一个事务去读一行,阻止其他事务获取相同数据集的排他锁
排他锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享锁和排他锁
4、RR和RC如何实现的?RR使用场景?对比volatile可见性,为什么RR的事务要设计成不能读另一个事务已经提交的数据?
隔离级别的单位是数据表还是数据行?如串行化级别,两个事务访问不同的数据行,能并发?
事务隔离级别为读提交时,写数据只会锁住相应的行
事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式是next-key 锁;如果检索条件没有索引,更新数据时会锁住整张表。一个间隙被事务加了锁,其他事务是不能在这个间隙插入记录的,这样可以防止幻读。
事务隔离级别为串行化时,读写数据都会锁住整张表
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
MYSQL MVCC实现机制参考链接:https://blog.csdn.net/whoamiyang/article/details/51901888
关于next-key 锁可以参考链接:https://blog.csdn.net/bigtree_3721/article/details/73731377**
存储引擎Innodb和Myisam的区别以及使用场景
区别:
MyISAM只支持表级锁,而InnoDB支持表级锁和行级锁
MyISAM不支持外键,而InnoDB支持外键
MyISAM不提供事务支持,而InnoDB提供事务支持
MyISAM 强调的是性能,每次查询具有原子性,其执行速度比 InnoDB 类型更快
MyISAM 在数据崩溃之后不能进行安全恢复,而InnoDB具备崩溃修复能力
因为 MyISAM 缓存有表 meta-data(行数等),因此在做 COUNT(*)时对于一个结构很好的查询是不需要消耗多少资源的。而对于 InnoDB 来说,则没有这种缓存
使用场景:
MyISAM 更适合读密集的表,而 InnoDB 更适合写密集的表。 在数据库做主从分离的情况下,经常选择 MyISAM 作为主库的存储引擎。
一般来说,如果需要事务支持,并且有较高的并发读取频率(MyISAM 的表锁的粒度太大,所以当该表写并发量较高时,要等待的查询就会很多了),InnoDB 是不错的选择。如果你的数据量很大(MyISAM 支持压缩特性可以减少磁盘的空间占用),而且不需要支持事务时,MyISAM 是最好的选择。
介绍Inodb锁机制,行锁,表锁,意向锁
mysql锁机制:
InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
Innodb 行级锁 record-level lock大致有三种:record lock, gap lock and Next-KeyLocks。
record lock 锁住某一行记录 gap lock 锁住某一段范围中的记录 next key lock 是前两者效果的叠加。
InnoDB实现了以下两种类型的行锁:
共享锁:允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁;
排他锁:允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(意向共享锁和意向排他锁)。这两种意向锁都是表锁。意向锁是InnoDB自动加的,不需要用户干预。 对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任意锁。
事务可以通过以下语句显示给记录集加共享锁或者排他锁:
SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE #共享锁
SELECT * FROM table_name WHERE ... FOR UPDATE #排他锁
InnoDB的行锁实现的特点:只有通过索引条件检索数据,InnoDB才会使用行级锁,否则,InnoDB将会使用表锁。因为MySQL的行锁是针对索引加的锁,
而不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引建,是会出现锁冲突的。
对于键值在条件范围内但并不存在的记录,叫做间隙。InnoDB会对这个间隙加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。 InnoDB使用间隙锁的目的:一是为了防止幻读,二是为了满足其恢复和复制的需要。
InnoDB如何解决死锁问题的:
在InnoDB中,锁是逐步获得的,因此发生死锁是可能的。发生死锁后,InnoDB一般都能自动检测到,并使一个事务释放锁并回退,另外一个事务获得锁,并继续完成事务。但在涉及外部锁, 或涉及表锁的情况下,InnoDB并不能完全自动检测到死锁,这需要通过设置锁等待超时参数innodb_lock_wait_timeout来解决。
介绍MVCC
https://blog.csdn.net/whoamiyang/article/details/51901888
哈希索引是如何实现的?
Hash索引:一对一主键 不利于范围查询 无法利用前缀查询
所谓Hash索引,当我们要给某张表某列增加索引时,将这张表的这一列进行哈希算法计算,得到哈希值,排序在哈希数组上。所以Hash索引可以一次定位,其效率很高
哈希索引(hash index)基于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。
哈希索引可细分为静态哈希和动态哈希这两大类
B树索引为什么使用B+树,相对于B树有什么优点?为什么不能红黑树?要提到磁盘预读
参考:http://www.liuzk.com/410.html
聚簇索引和非聚簇索引区别
1)聚簇索引
一个索引项直接对应实际数据记录的存储页,可谓“直达” 主键缺省使用它
索引项的排序和数据行的存储排序完全一致,利用这一点,想修改数据的存储顺序,可以通过改变主键的方法(撤销原有主键,另找也能满足主键要求的一个字段或一组字段,重建主键)
一个表只能有一个聚簇索引(理由:数据一旦存储,顺序只能有一种)
2) 非聚簇索引
不能“直达”,可能链式地访问多级页表后,才能定位到数据页
表数据存储顺序与索引顺序无关。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,其行数量与数据表行数据量一致。
一个表可以有多个非聚簇索引
回表查询和覆盖索引
回表查询:即先定位主键值,再根据主键值定位行记录,性能相对于只扫描一遍聚集索引树的性能要低一些。
覆盖索引:索引覆盖是一种避免回表查询的优化策略。具体的做法就是将要查询的数据作为索引列建立普通索引(可以是单列索引,也可以一个索引语句定义所有要查询的列,即联合索引),这样的话就可以直接返回索引中的的数据,不需要再通过聚集索引去定位行记录,避免了回表的情况发生。
覆盖索引的优点
索引条目通常远小于数据行的大小,因为覆盖索引只需要读取索引,极大地减少了数据的访问量。
索引是按照列值顺序存储的,对于IO密集的范围查找会比随机从磁盘读取每一行数据的IO小很多。
一些存储引擎比如MyISAM在内存中只缓存索引,数据则依赖操作系统来缓存,因此要访问数据的话需要一次系统调用,使用覆盖索引则避免了这一点。
由于InnoDB的聚簇索引,覆盖索引对InnoDB引擎下的数据库表特别有用。因为InnoDB的二级索引在叶子节点中保存了行的主键值,如果二级索引能够覆盖查询,就避免了对主键索引的二次查询。
参考:https://www.cnblogs.com/yanggb/p/11252966.html
如何创建索引?
主键索引(PRIMARY KEY):它是一种特殊的唯一索引,不允许有空值。一般在建表的时候同时创建主键索引。
-
唯一索引(UNIQUE):唯一索引列的值必须唯一,但允许有空值。
ALTER TABLE 表名 ADD UNIQUE(字段名)
-
普通索引(INDEX):最基本的索引,它没有任何限制。
ALTER TABLE 表名 ADD INDEX 索引名称(字段名称)
-
组合索引(INDEX):一个索引包含多个列,多用于避免回表查询。
ALTER TABLE 表名 ADD INDEX 索引名称(字段名称1,字段名称2,字段名称N)
-
全文索引(FULLTEXT):全文检索,是目前搜索引擎的一种关键技术,一般用于有大量的text类型数据的字段
ALTER TABLE student_register ADD FULLTEXT(字段名称)
如何使用索引避免全表扫描?
尽量不要使用like进行模糊查询,如果非要使用,尽量使用后导查询(左模糊like:...%)
应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
尽量避免在 where 子句中使用!=或< >操作符,否则将引擎放弃使用索引而进行全表扫描。
尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描
in 和 not in 也要慎用,否则会导致全表扫描
应考虑在 where 及 order by 涉及的列上建立索引。
Explain语句各字段的意义
- id
每个被独立执行的操作的标识,表示对象被操作的顺序;id值大,先被执行;如果相同,执行顺序从上到下。
若没有子查询和联合查询,id则都是1。Mysql会按照id从大到小的顺序执行query,在id相同的情况下,则从上到下执行。
- select_type
查询中每个select子句的类型
(1)SIMPLE
(2)PRIMARY/UNION
(3)DEPENDENT UNION/UNIOIN RESULT
(4)SUBQUERY/DEPENDENT SUBQUERY
(5)DERIVED/MATERIALIZED
(6)UNCACHEABLE SUBQUERY/UNCACHEABLE UNION
- table
名字,被操作的对象名称,通常是表名,或者表的别名,或者一个为查询产生临时表的标示符(如派生表、子查询、集合)。
- type
代表查询执行计划中表使用的连接方式。
连接操作类型及级别:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref。
- partitions
匹配的分区信息(对于非分区表值为NULL)。
- possible_keys
备选的索引(列出可能被使用到的索引)
- key
经优化器选定的索引;常用ANALYZE TABLE命令,可以使优化器正确地选择索引。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
- key_len
被优化器选定的索引键的长度,单位是字节。
- ref
表示本行被操作的对象的参照对象(被参照的对象可能是一个常量用const表示,也可能是其他表的key指向的对象)。
- rows
查询执行所扫描的元组个数(对于InnoDB,此值是估计值)。
- filtered
按照条件表上数据被过滤的元组个数的百分比,rows×filtered/100可以求出过滤后的元组数即实际的元组数。
- Extra
(1)using where
(2)using temporary
(3)using filesort
(4)using index
(5)using join buffer
(6)impossible where
(7)select tables optimized away
(8)distinct
最左前缀!!联合索引B+树是如何建立的?是如何查询的?当where子句中出现>时,联合索引命中是如何的? 如 where a > 10 and b = “111”时,联合索引如何创建?mysql优化器会针对得做出优化吗?
MySQL中一条SQL语句的执行过程
-
连接
SQL客户端与与服务器建立连接,该请求被发送到连接管理器,连接成功后会验证权限等,这过程其实就是一个TCP连接的过程。注意,MySQL服务器与客户端之间的通信是“半双工”的,意味着任意时刻,要么是服务器向客户端发送数据,要什么是客户端向服务器发送数据(请求),不能同时进行。
-
查询缓存
如果查询命中缓存(一个大小写敏感的哈希查找实现的)则直接返回结果(注意:在返回结果前还会检查一次用户号的权限);如果查询没有命中缓存,则进行下一步sql解析。
-
语法解析器和预处理
首先通过mysql关键字将语句解析,会生成一个内部解析树,mysql解析器将对其解析,查看是否是有错误的关键字,关键字顺序是佛正确; 预处理器则是根据mysql的规则进行进一步的检查,检查mysql语句是否合法,如,库表是否存在,字段是否存在,字段之间是否模棱两可等等,预处理器也会验证权限。
-
查询优化器
sql语句在优化器中转换成执行计划,一条sql语句可以有多种方式查询,最后返回的结果肯定是相同,但是不同的查询方式效果不同,优化器的作用就是:选择一种合适的执行计划 mysql是基于成本的优化器,他将预测执行此计划的成本,并选择成本最小的那条
-
执行计划
和很多关系型数据库不同的是,mysql不会产生查询字节码来执行查询,而是生成查询的一颗指令树,通过存储引擎执行指令并返回结果。最终的执行计划包含了重构查询的全部信息,通过EXPLAIN EXTENDED 和SHOW WARNINGS就可以看到重构的查询。
-
执行SQL
在解析和优化阶段,MySQL将生成查询对应的执行计划,由执行计划调用存储引擎的API来执行查询MySQL就行(在此过程中只是简单的根据执行计划给出的指令逐步执行) 将结果返回给客户端;即使查询不需要返回结果,MySQL也会返回影响到的行数。注意:返回结果时是个逐步返回结果的过程,并不是一次性查询完然后返回一个大的结果集
https://zhuanlan.zhihu.com/p/70295845
数据库几大范式
第一范式:列不可再分,数据表的每一个字段都具备原子性,不能在进行分割
第二范式:在第一范式的基础之上,数据表的每一行数据有一个可进行标识的主属性字段(主键),该行的其余字段都应全部依赖于该主属性字段(主键),如果存在不依赖于该主键的字段,必须将其分离出去
第三范式:在第二范式的基础之上,针对于数据的冗余性,表与表之间的数据引用关系,若存在两张数据表A和B,B的字段中出现了A的主键,则B中不能再出现A中依赖于其主键的其它字段(即不能有依赖传递)
反范式:指不遵循三大范式,通过增加冗余或重复的数据来提高数据库的读性能。反范式可以减轻数据库的关联查找所带来的负担