目录
MySQL事务
事务的特性
并发事务的问题?
事务隔离级别?
MySQL索引
数据结构
索引类型
聚簇索引与非聚簇索引
聚集索引的优点
聚集索引的缺点
非聚集索引的优点
非聚集索引的缺点
非聚集索引一定回表查询吗(覆盖索引)?
覆盖索引
联合索引
最左前缀匹配原则
创建索引的注意事项
什么时候别用索引?
索引优化
索引失效
MySQL事务
定义:多条sql语句,要么全部成功,要么全部失败。
事务的特性
数据库事务特性:原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)、持久性(Durabiliy)。简称ACID。
-
原子性:组成一个事务的多个数据库操作不可分割,只有所有操作都成功,整个事务才会提交。任何一个操作失败,已经执行的任何操作都必须撤销,让数据库返回初始状态。
-
一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的。即数据不会被破坏。如A转账100元给B,不管操作是否成功,A和B的账户总额是不变的。
-
隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对彼此产生干扰
-
持久性:一旦事务提交成功,事务中的所有操作都必须持久化到数据库中。
并发事务的问题?
-
脏读: 如果一个事务「读到」了另一个「未提交事务修改过的数据」,就意味着发生了「脏读」现象。
-
丢失修改: 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
-
例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
-
-
不可重复读: 指在一个事务内多次读同一数据,在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就造成在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
-
幻读: 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复读和幻读区别:
不可重复读的重点是修改,幻读的重点在于新增或者删除
事务隔离级别?
SQL 标准定义了四个隔离级别:
-
(读未提交): 最低的隔离级别,允许读取尚未提交的数据,可能会导致脏读、幻读或不可重复读。
-
(读已提交): 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
-
(可重复读): 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
-
(可串行化): 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交 | √ | √ | √ |
读取已提交 | × | √ | √ |
可重复读 | × | × | √ |
可串行化 | × | × | × |
MySQL的默认隔离级别是可重复读
MySQL索引
索引是一种用于快速查询和检索数据的数据结构,其本质可以看成是一种排序好的数据结构。
优点:
-
使用索引可以大大加快数据的检索速度(大大减少检索的数据量), 这也是创建索引的最主要的原因。
-
通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
缺点:
-
创建索引和维护索引需要耗费许多时间。当对表中的数据进行增删改的时候,如果数据有索引,那么索引也需要动态的修改,会降低 SQL 执行效率。
-
索引需要使用物理文件存储,也会耗费一定空间。
数据结构
-
Hash表
哈希表是键值对的集合,通过键(key)即可快速取出对应的值(value),因此哈希表可以快速检索数据,接近 O(1)。
为什么MySQL 没用它?
1.Hash 冲突问题 :我们上面也提到过Hash 冲突了,不过对于数据库来说这还不算最大的缺点。
2.Hash 索引不支持顺序和范围查询,这是它最大的缺点: 假如我们要对表中的数据进行排序或者进行范围查询,那 Hash 索引可就不行了。
-
B & B+
B 树& B+树两者有何异同呢?
-
B 树的所有节点既存放键(key) 也存放 数据(data),而 B+树只有叶子节点存放 key 和 data,其他内节点只存放 key。
-
B 树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点。
-
B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显。
-
索引类型
-
主键索引 : 数据表的主键列使用的就是主键索引
-
二级索引(辅助索引) : 因为二级索引的叶子节点存储的数据是主键。也就是说,通过二级索引,可以定位主键的位置。
-
唯一索引 :唯一索引也是一种约束。唯一索引的属性列不能出现重复的数据,但是允许数据为 NULL,一张表允许创建多个唯一索引。 建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。
-
普通索引 :普通索引的唯一作用就是为了快速查询数据,一张表允许创建多个普通索引,并允许数据重复和 NULL。
-
前缀索引 :前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小, 因为只取前几个字符。
-
全文索引 :全文索引主要是为了检索大文本数据中的关键字的信息,是目前搜索引擎数据库使用的一种技术。Mysql5.6 之前只有 MYISAM 引擎支持全文索引,5.6 之后 InnoDB 也支持了全文索引。
-
聚簇索引与非聚簇索引
聚集索引就是索引结构和数据一起存放的索引。主键索引属于聚集索引。
聚集索引的优点
聚集索引的查询速度非常的快,因为整个 B+树本身就是一颗多叉平衡树,叶子节点也都是有序的,定位到索引的节点,就相当于定位到了数据。
聚集索引的缺点
-
依赖于有序的数据 :因为 B+树是多路平衡树,如果索引的数据不是有序的,那么就需要在插入时排序,如果数据是整型还好,否则类似于字符串或 UUID 这种又长又难比较的数据,插入或查找的速度肯定比较慢。
-
更新代价大 : 如果对索引列的数据被修改时,那么对应的索引也将会被修改,而且聚集索引的叶子节点还存放着数据,修改代价肯定是较大的,所以对于主键索引来说,主键一般都是不可被修改的
非聚集索引即索引结构和数据分开存放的索引 , 二级索引属于非聚集索引。
非聚集索引的叶子节点并不一定存放数据的指针,因为二级索引的叶子节点就存放的是主键,根据主键再回表查数据。
非聚集索引的优点
-
更新代价比聚集索引要小
非聚集索引的缺点
-
跟聚集索引一样,非聚集索引也依赖于有序的数据
-
可能会二次查询(回表) :这应该是非聚集索引最大的缺点了。 当查到索引对应的指针或主键后,可能还需要根据指针或主键再到数据文件或表中查询。
非聚集索引一定回表查询吗(覆盖索引)?
非聚集索引不一定回表查询。
主键索引本身的 key 就是主键,查到返回就行了。这种情况就称之为覆盖索引了。
例如 : SELECT id FROM table WHERE id=1;
覆盖索引
覆盖索引就是说需要查询的字段正好是索引的字段,那么直接根据该索引,就可以查到数据了, 而无需回表查询。
联合索引
使用表中的多个字段创建索引,就是 联合索引,也叫 组合索引 或 复合索引。
最左前缀匹配原则
最左前缀匹配原则指的是,在使用联合索引时,MySQL 会根据联合索引中的字段顺序,从左到右依次到查询条件中去匹配,如果查询条件中存在与联合索引中最左侧字段相匹配的字段,则就会使用该字段过滤一批数据,直至联合索引中全部字段匹配完成,或者在执行过程中遇到范围查询(如 >
、<
)才会停止匹配。对于 >=
、<=
、BETWEEN
、like
前缀匹配的范围查询,并不会停止匹配。所以,我们在使用联合索引时,可以将区分度高的字段放在最左边,这也可以过滤更多数据。
创建索引的注意事项
-
选择合适的字段
-
不为NULL的字段 , 如果需要 , 使用0 , 1 , true , false来代替
-
被频繁查询的字段
-
被作为条件查询的字段
-
频繁需要排序的字段
-
频繁连接的字段
-
-
被频繁更新的字段应谨慎建立索引
-
尽量考虑联合索引而非单列索引
-
尽量避免冗余索引
-
能够命中索引(a, b)就肯定能命中索引(a) ,那么索引(a)就是冗余索引
-
什么时候别用索引?
-
经常增删改的列不要建立索引;
-
有大量重复的列不建立索引;
-
表记录太少不要建立索引
索引优化
-
前缀索引优化;
-
前缀索引顾名思义就是使用某个字段中字符串的前几个字符建立索引,那为什么需要使用前缀来建立索引呢?
使用前缀索引是为了减小索引字段大小,可以增加一个索引页中存储的索引值,有效提高索引的查询速度。在一些大字符串的字段作为索引时,使用前缀索引可以帮助我们减小索引项的大小。
-
-
覆盖索引优化;
-
覆盖索引是指 SQL 中 query 的所有字段,在索引 B+Tree 的叶子节点上都能找得到的那些索引,从二级索引中查询得到记录,而不需要通过聚簇索引查询获得,可以避免回表的操作。
-
-
主键索引最好是自增的;
-
如果我们使用自增主键,那么每次插入的新数据就会按顺序添加到当前索引节点的位置,不需要移动已有的数据,当页面写满,就会自动开辟一个新页面。因为每次插入一条新记录,都是追加操作,不需要重新移动数据,因此这种插入数据的方法效率非常高。
如果我们使用非自增主键,由于每次插入主键的索引值都是随机的,因此每次插入新的数据时,就可能会插入到现有数据页中间的某个位置,这将不得不移动其它数据来满足新数据的插入,甚至需要从一个页面复制数据到另外一个页面,我们通常将这种情况称为页分裂。页分裂还有可能会造成大量的内存碎片,导致索引结构不紧凑,从而影响查询效率。
-
-
防止索引失效;
-
发生索引失效的情况:
-
当我们使用左或者左右模糊匹配的时候,也就是
like %xx
或者like %xx%
这两种方式都会造成索引失效; -
当我们在查询条件中对索引列做了计算、函数、类型转换操作,这些情况下都会造成索引失效;
-
联合索引要能正确使用需要遵循最左匹配原则,也就是按照最左优先的方式进行索引的匹配,否则就会导致索引失效。
-
在 WHERE 子句中,如果在 OR 前的条件列是索引列,而在 OR 后的条件列不是索引列,那么索引会失效。
-
-
索引失效
1、使用!= 或 <>
2、最左前缀原则
3、字段类型不一致索引失效
4、函数导致索引失效
5、运算符导致索引失效
如果你对列进行了(+,-,*,/,!), 那么都将不会走索引。
SELECT * FROM user
WHERE age - 1 = 20;
6、or引起索引失效
7、模糊查询导致索引失效
SELECT * FROM user
WHERE name
LIKE '%冰';
模糊搜索如果你前缀也进行模糊搜索,那么不会走索引。
9、IS NULL不走索引,IS NOT NULL走索引