优质文章
MySQL 可重复读隔离级别,完全解决幻读了吗? | 小林coding (xiaolincoding.com)

预处理阶段的语法树的结构


用于建立客户端于服务器之间的连接,相当于客户端获取到了数据库的管理权限
一个SQL语句首先会到缓存中查看这条语句之前是否被查询过(如果开启了查询缓存功能),如果查询过直接返回缓存中的结果给客户端。
该机制的优点是如果命中的话,效率很高。缺点是缓存失效的频率太高,只要表一进行更新,该表的所以查询缓存都会被清空,因为该缺点,MySQL 8.0 版本已经删除了查询缓存功能
对SQL语句进行词法和语法的分析,并构造出语法树,方便预处理阶段检查字段和表是否存在
*展开,检查字段和表是否存在
选择合适的索引,制定代价最小的查询计划
根据执行计划执行SQL语句,调用存储引擎接口,返回最终的结果给客户端
存储引擎层主要负责对数据的存取
其架构是存入式的,意味着你可以根据具体的需要来选择存储引擎
创建的存储引擎有InnoDB和MyISAM等。
MySQL 5.5.5版本开始默认的是InoDB,如果想使用其他存储引擎可以通过engine = MyISAM类似这种形式来切换。
首先需要通过连接器,建立客户端与服务器之间的连接,获得数据库的管理权限
如果查询缓存功能开启的话,会先去查询缓存,如果命中了,直接返回缓存种的结果给客户端。说一下给功能的优缺点,优点如果命中了查询效率会特别高,缺点,缓存失效太频繁,只要表一更新,查询缓存就会清空,8.0版本以取消该功能
如果没有命中,会通过分析器,对SQL语句进行词法语法的分析,并建立语法树
然后通过预处理器,把通配符展开,并检查字段和表是否存在
然后通过优化器,对SQL语句进行优化,选择合适的索引,指定查询代价最小的执行计划
然后通过执行器,判断对该表是否有执行权限,如果根据执行计划执行SQL语句,调用存储引擎接口,然会调用后的结果返回给客户端
在存储引擎种只要进行数据的存取工作,由于存储引擎的架构是插入时的,所以可以更改存储引擎。从5.5.5版本之后的存储引擎都是InnoDB,如果有特别需要,可以通过engine = MyISAM更改存储引擎
原子性(数据库中存储的数据是不可再分的)

唯一性(消除非主键部分依赖于联合主键中的一部分字段)
非主键外的其他字段必须完全依赖于主键,不能部分依赖于主键
比如现在有一个联合主键(a,b),有a才能有c,那么现在说明c依赖于a,但是c不依赖于b,所以c是部分依赖于主键的,不符合第三范式
比如这个例子,如果有主键的说应该是(学生,课程)的联合主键,但是明显其他字段对联合主键是部分依赖,所以不符合第三范式
解决方法
消除传递性依赖,比如B依赖于A,C也依赖于A,但C不能依赖于B。

解决方法,分表

范式不是绝对要求的,有的时候为了满足需求还会特意违反范式。
细说varchar与char有哪些区别?_char和varchar区别-CSDN博客
char和varchar都是用来存储字符串的
char(n):固定长度类型,存储的长度不足n时,自动补空间,查询的时候自动删空间
适用于固定长度的字符类型存储,比如密码
最大存储容量为255B
varchar(n):不定长类型
如果类的长度小于255用一个字节记录长度,大于用2个字节记录
最大存储容量为65535
varchar(100) 会额外占用1个字节存储长度
varchar(1000)会额外占用2个字节存储长度
这样看到似乎存储长度设置的越大越好,反正占用的存储空间都是实际的字符大小。在磁盘上看是这样的,磁盘上分配的空间是按实际长度来分配的,但是内存上的空间是按设置的长度来分配的。但是在创建临时表或者排序的时候,是按内存中的长度排序的
可以提高查找效率,就好比目录和字典的关系,有了目录我们才能快速在字段点中查找文字
索引的创建和维护都需要消耗时间和物理空间。增删改查的时候索引也要动态维护,大大降低了维护的效率
在使用最频繁的,可以缩小查找范围、需要排序的字段上建立索引
使用频率很少的列或者重复值很多的列不适合建立索引
对于一些特殊的数据类型,不宜创建索引,比如text因为太大了,索引的创建和维护是需要占用物理空间的
使用倒排算法具体不清楚
基于哈希表实现的,查找非常迅速,但是不支持范围查找和排序。如果哈希冲突很多的话,索引的维护代价会比较高。哈希索引属于自适应类型的索引,不能认为创建。
B+树索引是按照顺序组织存储的,所以适合范围查找和排序。
B+树索引分为聚簇索引和非聚簇索引(二级索引要回表)
最开始是二叉搜索树,它时按左下 上 右下 一次是小中大的这种形式递归存储的 但是如果数据按大小排序存储的话,会退化成一个链表
然后是平衡二叉树,但是平衡二叉树存储数据树的层数太高了,磁盘的IO次数太多,查询效率低
然后是B树,它是平衡多叉树,一个结点的子树可以有多个,树的高度大大降低了,磁盘IO次数减少,查询效率边高了
最后是B+树,他是一种特殊的平衡多叉树,非叶子结点存索引,叶子阶段存索引和数据。对于非叶子结点而言,存储索引显而易见更节省空间,所以树的层数会特别的少,磁盘IO次数也很少,查询效率高。并且B+树的叶子结点意见用双向链表连接了,支持范围查找和排序

B+树进行查找操作时,会在根节点进行二分搜查找,找到一个key所在的指针,然后递归的进行二分查找,直到找到了叶子结点,然后在叶子结点上二分查找,直到找出key所对应data
B+树输入删除的适合会破坏平衡性,因此在插入删除操作之后需要对树进行一个分类、合并、旋转等操作来维护平衡性,维护代价较高
索引会被多次存储
只有叶子存放数据,其他非叶子结点存放索引。相比于B树,这种存储模式会使树的高度减少非常多,即使是上千万的数据只需要三四层高度就可以满足,查询一个数据仅需要3到4次磁盘I/O。
由于数据都在叶子结点上,所以B+树只有遍历到最底层才能找到数据,查找效率稳定在O(nlogn)
B+树的叶子结点用双向链表连接在一起,更加适合于范围查找,而B树需要通过中序遍历来扫描,B+树范围查找的效率更高


因为一般主键为聚簇索引,一般设置自增的主键就是因为这个原因
所以选择与业务无关的列作为主键
B+树会把一个叶子结点优化成一个磁盘块,突然插入一条数据可能磁盘块放不下了,自增
哈希索引是基于哈希表的一种索引结构,如果命中的话,可以在O(1)时间进行查找,但是由于其无序性,无法进行范围查找和排序。
InnoDB存储引擎有一个特殊的功能叫自适应哈希索引,当一个索引值被频繁查找的时候,会在B+上索引上再建立一个哈希索引,这样就让B+树索引具有了哈希索引的一些特点,比如快速哈希查找

(name,age)的联合索引–>创建了(name)、(age)的索引
(name、age、sex)的联合索引–>创建了(name)、(name,age)、(name、age、sex)的索引
索引下推
现在我们知道,对于联合索引(a, b),在执行 select * from table where a > 1 and b = 2 语句的时候,只有 a 字段能用到索引,那在联合索引的 B+Tree 找到第一个满足条件的主键值(ID 为 2)后,还需要判断其他条件是否满足(看 b 是否等于 2),那是在联合索引里判断?还是回主键索引去判断呢?
在 MySQL 5.6 之前,只能从 ID2 (主键值)开始一个个回表,到「主键索引」上找出数据行,再对比 b 字段值。
而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在联合索引遍历过程中,对联合索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
当你的查询语句的执行计划里,出现了 Extra 为 Using index condition,那么说明使用了索引下推的优化。
在(a,b,c,d)的联合索引中,where a = 1 and b = 2 and c > 3 and d = 4
会用到a b c 的索引,d是用不到索引的
explain+查询的这条语句,一条MySQL语句经历分析器、优化器、执行器,其中尽力优化器的时候会拿到这条语句的分析。
create index ename_idex on emp(ename);
create index sal_idex on emp(sal);
#All全文查找
explain select * from emp;
#ename_idex
explain select ename from emp;
#sal_index
explain select empno from emp;
#ename_index
explain select empno from where ename = 'smith';
#primary key index
explain select ename from emp where empno = 7396;
#ALL 索引失效 or 有一边没用到索引
explain select * from emp where job = 'clerk' or ename = 'clerk';
#ALL 索引失效 or 有一边没用到索引
explain select empno from emp where empno = 7396 or job = 'clerk';
#empno_index、sal_index
explain select * from emp where empno = 7396 or sal > 5000;
#索引使用不等于相当于全文查找了,用索引没有意义
explain select * from emp where sal != 5000;
#索引使用不等于相当于全文查找了,用索引没有意义
explain select * from emp where sal > 5000 or sal <5000;
#like模糊查询,不查开头,查其他情况会导致所以索引失效
explain select * from emp where ename like '%s%';
#索引参与计算,会导致索引失效
explain select * from emp where sal + 1 > 5000;
(事务:一组原子性的SQL查询,事务要么全部成功,要么全部执行失败,如果失败了前面执行成功的也要回滚,DML语句的执行代表事务的开始,事务的结束要么是提交事务即全部执行成功,要么是回滚执行失败)
student score
constraint fk1 foreign key (student_id) references stduent(id);
水平切割就是将一个表中的记录水平切分成多个结构相同的表
当一个表中的数据不断增多的时候,水平切割时必然的,它可以减缓单个数据库的压力
垂直切割就时将一个表中的列切分成多个表,通常时按照列于列之间的紧密程度进行切割的,将尝试用的放在一个表,不常使用的放在一个表中
主要负责将主服务器上数据的更改写到binary log(二进制日志)文件中
读取BinLog日志文件中的的内容,并写入从服务器RelayLog日志文件中
负责读取RelayLog日志文件中的内容,并重放其中的SQL语句


事务时最小工作单元,不可再分,事务中的SQL语句要么全部执行成功,要么全部失败回滚。
就好比你在超市中买东西,你拿了一些商品去付款。要么付款成功你把东西拿走,钱给老板。要么付款失败,你的东西要还给老板,也无需付款,就像你刚开始来超市一样
数据库总时由一个状态到另外一个状态,不会由于某条语句的失败而出现其他状态
就比如你有400元,你的朋友有600元,你想给你朋友转账。最后的结果一定是你200,朋友800。不能出现你200,你朋友600这种中间状态
通常来说,一个事务在没提交之前,对其他事务时不可见的
事务一旦提交,其做的修改会持久的保存到数据库中。


最低的隔离级别,一个事务没提交就可以被其他事务读到
可能会导致脏读、不可重复读、幻读等问题
可以解读脏读问题,但是仍会产生不可重复度和幻读问题
在一个事务中,对一个字段多次读取的结果都是一样的。可以解决脏读和不可重复读问题,但是无法彻底解决幻读问题
一个事务执行完之后另外一个事务才能执行,完全服从ACID隔离级别,可以解决脏读、不可重复度、幻读问题
表示一个事务还没有提交,就被另外一个事务读到了。由于未提交的事务可能会回滚,另外一个事务读到的数据就是脏数据
在一个事务中,俩次读取到的结果不一样,因为另外一个事务提交修改了要读取的数据。
不可重复读重点是在修改,同样的条件,多次读取结果不同
幻读重点在于新增和删除:同样的条件,第一次和第二次读出来的记录数不一样

1.读-读:不存在任何问题,也不需要并发控制
2.读-写:存在线程安全问题,可能会造成事务的隔离级别,可能会遇到脏读、幻读、不可重复读
3.写-写:有线程安全问题,可能会造成数据更新丢失问题
1.快照读(普通的select语句):是通过MVCC方式解决幻读问题的,因为再可重复读隔离级别下,事务执行过程中所看到的数据都是事务启动时的数据,即使中途其他是我对数据进行了修改,是查不出该事务的。因为读取的都是其实启动时的数据,所以这就很好避免了幻读问题
2.当前读(select … for update 等语句),是通过next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select … for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
1.使用show processlist 命令查看当前所有连接信息
2.使用explain命令查询SQL语句的执行计划
3.开启慢查询日志,查看慢查询的SQL


优点:有了范式可以减少数据的冗余,数据表更新操作快、占用的内容少
缺点:为了满足三范式会进行分表,查询时通常需要连表查,更难进行索引优化
优点:数据都在一个表中,可以减少表关联,更好进行索引优化
缺点:存在大量的冗余数据,数据的维护成本更高
select id, name from emp where id > 1000000 limit 10;
select id, name from emp where id ( select id from limit 1000000, 1 )limit 10;
select id, name from emp order by limit 1000000, 10;
内连接是在俩个表连表查询的时候,只保留完全匹配的结果集
连表查询的时候,不但保留完全匹配的结果集还有左表中的所有行
连表查询的时候,不但保留完全匹配的结果集还有右表中的所有行
聚合函数自动忽略空值
聚合函数在where之后使用,因为where遍历表的时候聚合函数还有算出来结果那


将多个列组合成一个索引,该索引就被成为联合索引
在InnoDB的存储引擎下,默认的索引结构是B+树结构,也就是说非叶子结点存储的是联合索引,叶子节点,存储的是联合索引和主键
因为联合索引在创建B+树索引的时候,顺序是先按第一个字段排序,如果第一个字段相同再按第二个字段排序。这也就导致了其他字段的顺序依赖于最左边的第一个字段
所以说如果你的where查询条件不是从最左边开始的,就无法使用索引
例如:创建了(a,b,c)的联合索引,你的where 条件 是b c怎么怎么样就无法用到bc索引,因为bc再B+树种是没有顺序的,它依赖于a的顺序
还有就是范围查找后面的字段会索引失效
比如 (a,b,c) where a=1 and b>2 and c = 3;
这种情况就无法使用到了c索引,因为范围查找实际上是按照链表进行遍历,等遍历到b>2的时候,c以及无序了
索引下推是在5.6版本以后引入的,目的是在联合索引遍历的过程中,如果第一个字段相同,那么不用回表找第二个字段,直接在联合索引的B+树种就能判断是否满足条件。
另外,建立联合索引时的字段顺序,对索引效率也有很大影响。越靠前的字段被用于索引过滤的概率越高,实际开发工作中建立联合索引时,要把区分度大的字段排在前面,这样区分度大的字段越有可能被更多的 SQL 使用到。
区分度就是某个字段 column 不同值的个数「除以」表的总行数,计算公式如下:

比如,性别的区分度就很小,不适合建立索引或不适合排在联合索引列的靠前的位置,而 UUID 这类字段就比较适合做索引或排在联合索引列的靠前的位置。
因为如果索引的区分度很小,假设字段的值分布均匀,那么无论搜索哪个值都可能得到一半的数据。在这些情况下,还不如不要索引,因为 MySQL 还有一个查询优化器,查询优化器发现某个值出现在表的数据行中的百分比(惯用的百分比界线是"30%")很高的时候,它一般会忽略索引,进行全表扫描。
对于长度很长的字段如果非要创建索引的话,最好创建前缀索引,就是选该字段的一部分作为索引,但是要保证该部分具有高选择性
覆盖索引二级索引查询查询数据的时候,不用回表就查询到想要的数据的一种现场。
顺序插入可以减少索引的维护代价,而且可以预防页分裂的现象
1.or的左右两边不都是索引
2.where后面的条件是!=这种
3.like ‘%s’ ‘%s%’
假设你建立了name字段的索引,那么name字段作为索引在B+树上的顺序是有序的,但是如果你不是从第一个字母去比较的话,索引就会失效,因为它变得无序了
4.索引列参与计算了
5.索引列放在函数里面了
6.使用联合索引的时候,没有遵循最左前缀原则
优质文章
MySQL 可重复读隔离级别,完全解决幻读了吗? | 小林coding (xiaolincoding.com)

预处理阶段的语法树的结构


用于建立客户端于服务器之间的连接,相当于客户端获取到了数据库的管理权限
一个SQL语句首先会到缓存中查看这条语句之前是否被查询过(如果开启了查询缓存功能),如果查询过直接返回缓存中的结果给客户端。
该机制的优点是如果命中的话,效率很高。缺点是缓存失效的频率太高,只要表一进行更新,该表的所以查询缓存都会被清空,因为该缺点,MySQL 8.0 版本已经删除了查询缓存功能
对SQL语句进行词法和语法的分析,并构造出语法树,方便预处理阶段检查字段和表是否存在
*展开,检查字段和表是否存在
选择合适的索引,制定代价最小的查询计划
根据执行计划执行SQL语句,调用存储引擎接口,返回最终的结果给客户端
存储引擎层主要负责对数据的存取
其架构是存入式的,意味着你可以根据具体的需要来选择存储引擎
创建的存储引擎有InnoDB和MyISAM等。
MySQL 5.5.5版本开始默认的是InoDB,如果想使用其他存储引擎可以通过engine = MyISAM类似这种形式来切换。
首先需要通过连接器,建立客户端与服务器之间的连接,获得数据库的管理权限
如果查询缓存功能开启的话,会先去查询缓存,如果命中了,直接返回缓存种的结果给客户端。说一下给功能的优缺点,优点如果命中了查询效率会特别高,缺点,缓存失效太频繁,只要表一更新,查询缓存就会清空,8.0版本以取消该功能
如果没有命中,会通过分析器,对SQL语句进行词法语法的分析,并建立语法树
然后通过预处理器,把通配符展开,并检查字段和表是否存在
然后通过优化器,对SQL语句进行优化,选择合适的索引,指定查询代价最小的执行计划
然后通过执行器,判断对该表是否有执行权限,如果根据执行计划执行SQL语句,调用存储引擎接口,然会调用后的结果返回给客户端
在存储引擎种只要进行数据的存取工作,由于存储引擎的架构是插入时的,所以可以更改存储引擎。从5.5.5版本之后的存储引擎都是InnoDB,如果有特别需要,可以通过engine = MyISAM更改存储引擎
原子性(数据库中存储的数据是不可再分的)

唯一性(消除非主键部分依赖于联合主键中的一部分字段)
非主键外的其他字段必须完全依赖于主键,不能部分依赖于主键
比如现在有一个联合主键(a,b),有a才能有c,那么现在说明c依赖于a,但是c不依赖于b,所以c是部分依赖于主键的,不符合第三范式
比如这个例子,如果有主键的说应该是(学生,课程)的联合主键,但是明显其他字段对联合主键是部分依赖,所以不符合第三范式
解决方法
消除传递性依赖,比如B依赖于A,C也依赖于A,但C不能依赖于B。

解决方法,分表

范式不是绝对要求的,有的时候为了满足需求还会特意违反范式。
细说varchar与char有哪些区别?_char和varchar区别-CSDN博客
char和varchar都是用来存储字符串的
char(n):固定长度类型,存储的长度不足n时,自动补空间,查询的时候自动删空间
适用于固定长度的字符类型存储,比如密码
最大存储容量为255B
varchar(n):不定长类型
如果类的长度小于255用一个字节记录长度,大于用2个字节记录
最大存储容量为65535
varchar(100) 会额外占用1个字节存储长度
varchar(1000)会额外占用2个字节存储长度
这样看到似乎存储长度设置的越大越好,反正占用的存储空间都是实际的字符大小。在磁盘上看是这样的,磁盘上分配的空间是按实际长度来分配的,但是内存上的空间是按设置的长度来分配的。但是在创建临时表或者排序的时候,是按内存中的长度排序的
可以提高查找效率,就好比目录和字典的关系,有了目录我们才能快速在字段点中查找文字
索引的创建和维护都需要消耗时间和物理空间。增删改查的时候索引也要动态维护,大大降低了维护的效率
在使用最频繁的,可以缩小查找范围、需要排序的字段上建立索引
使用频率很少的列或者重复值很多的列不适合建立索引
对于一些特殊的数据类型,不宜创建索引,比如text因为太大了,索引的创建和维护是需要占用物理空间的
使用倒排算法具体不清楚
基于哈希表实现的,查找非常迅速,但是不支持范围查找和排序。如果哈希冲突很多的话,索引的维护代价会比较高。哈希索引属于自适应类型的索引,不能认为创建。
B+树索引是按照顺序组织存储的,所以适合范围查找和排序。
B+树索引分为聚簇索引和非聚簇索引(二级索引要回表)
最开始是二叉搜索树,它时按左下 上 右下 一次是小中大的这种形式递归存储的 但是如果数据按大小排序存储的话,会退化成一个链表
然后是平衡二叉树,但是平衡二叉树存储数据树的层数太高了,磁盘的IO次数太多,查询效率低
然后是B树,它是平衡多叉树,一个结点的子树可以有多个,树的高度大大降低了,磁盘IO次数减少,查询效率边高了
最后是B+树,他是一种特殊的平衡多叉树,非叶子结点存索引,叶子阶段存索引和数据。对于非叶子结点而言,存储索引显而易见更节省空间,所以树的层数会特别的少,磁盘IO次数也很少,查询效率高。并且B+树的叶子结点意见用双向链表连接了,支持范围查找和排序

B+树进行查找操作时,会在根节点进行二分搜查找,找到一个key所在的指针,然后递归的进行二分查找,直到找到了叶子结点,然后在叶子结点上二分查找,直到找出key所对应data
B+树输入删除的适合会破坏平衡性,因此在插入删除操作之后需要对树进行一个分类、合并、旋转等操作来维护平衡性,维护代价较高
索引会被多次存储
只有叶子存放数据,其他非叶子结点存放索引。相比于B树,这种存储模式会使树的高度减少非常多,即使是上千万的数据只需要三四层高度就可以满足,查询一个数据仅需要3到4次磁盘I/O。
由于数据都在叶子结点上,所以B+树只有遍历到最底层才能找到数据,查找效率稳定在O(nlogn)
B+树的叶子结点用双向链表连接在一起,更加适合于范围查找,而B树需要通过中序遍历来扫描,B+树范围查找的效率更高


因为一般主键为聚簇索引,一般设置自增的主键就是因为这个原因
所以选择与业务无关的列作为主键
B+树会把一个叶子结点优化成一个磁盘块,突然插入一条数据可能磁盘块放不下了,自增
哈希索引是基于哈希表的一种索引结构,如果命中的话,可以在O(1)时间进行查找,但是由于其无序性,无法进行范围查找和排序。
InnoDB存储引擎有一个特殊的功能叫自适应哈希索引,当一个索引值被频繁查找的时候,会在B+上索引上再建立一个哈希索引,这样就让B+树索引具有了哈希索引的一些特点,比如快速哈希查找

(name,age)的联合索引–>创建了(name)、(age)的索引
(name、age、sex)的联合索引–>创建了(name)、(name,age)、(name、age、sex)的索引
索引下推
现在我们知道,对于联合索引(a, b),在执行 select * from table where a > 1 and b = 2 语句的时候,只有 a 字段能用到索引,那在联合索引的 B+Tree 找到第一个满足条件的主键值(ID 为 2)后,还需要判断其他条件是否满足(看 b 是否等于 2),那是在联合索引里判断?还是回主键索引去判断呢?
在 MySQL 5.6 之前,只能从 ID2 (主键值)开始一个个回表,到「主键索引」上找出数据行,再对比 b 字段值。
而 MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在联合索引遍历过程中,对联合索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
当你的查询语句的执行计划里,出现了 Extra 为 Using index condition,那么说明使用了索引下推的优化。
在(a,b,c,d)的联合索引中,where a = 1 and b = 2 and c > 3 and d = 4
会用到a b c 的索引,d是用不到索引的
explain+查询的这条语句,一条MySQL语句经历分析器、优化器、执行器,其中尽力优化器的时候会拿到这条语句的分析。
create index ename_idex on emp(ename);
create index sal_idex on emp(sal);
#All全文查找
explain select * from emp;
#ename_idex
explain select ename from emp;
#sal_index
explain select empno from emp;
#ename_index
explain select empno from where ename = 'smith';
#primary key index
explain select ename from emp where empno = 7396;
#ALL 索引失效 or 有一边没用到索引
explain select * from emp where job = 'clerk' or ename = 'clerk';
#ALL 索引失效 or 有一边没用到索引
explain select empno from emp where empno = 7396 or job = 'clerk';
#empno_index、sal_index
explain select * from emp where empno = 7396 or sal > 5000;
#索引使用不等于相当于全文查找了,用索引没有意义
explain select * from emp where sal != 5000;
#索引使用不等于相当于全文查找了,用索引没有意义
explain select * from emp where sal > 5000 or sal <5000;
#like模糊查询,不查开头,查其他情况会导致所以索引失效
explain select * from emp where ename like '%s%';
#索引参与计算,会导致索引失效
explain select * from emp where sal + 1 > 5000;
(事务:一组原子性的SQL查询,事务要么全部成功,要么全部执行失败,如果失败了前面执行成功的也要回滚,DML语句的执行代表事务的开始,事务的结束要么是提交事务即全部执行成功,要么是回滚执行失败)
student score
constraint fk1 foreign key (student_id) references stduent(id);
水平切割就是将一个表中的记录水平切分成多个结构相同的表
当一个表中的数据不断增多的时候,水平切割时必然的,它可以减缓单个数据库的压力
垂直切割就时将一个表中的列切分成多个表,通常时按照列于列之间的紧密程度进行切割的,将尝试用的放在一个表,不常使用的放在一个表中
主要负责将主服务器上数据的更改写到binary log(二进制日志)文件中
读取BinLog日志文件中的的内容,并写入从服务器RelayLog日志文件中
负责读取RelayLog日志文件中的内容,并重放其中的SQL语句


事务时最小工作单元,不可再分,事务中的SQL语句要么全部执行成功,要么全部失败回滚。
就好比你在超市中买东西,你拿了一些商品去付款。要么付款成功你把东西拿走,钱给老板。要么付款失败,你的东西要还给老板,也无需付款,就像你刚开始来超市一样
数据库总时由一个状态到另外一个状态,不会由于某条语句的失败而出现其他状态
就比如你有400元,你的朋友有600元,你想给你朋友转账。最后的结果一定是你200,朋友800。不能出现你200,你朋友600这种中间状态
通常来说,一个事务在没提交之前,对其他事务时不可见的
事务一旦提交,其做的修改会持久的保存到数据库中。


最低的隔离级别,一个事务没提交就可以被其他事务读到
可能会导致脏读、不可重复读、幻读等问题
可以解读脏读问题,但是仍会产生不可重复度和幻读问题
在一个事务中,对一个字段多次读取的结果都是一样的。可以解决脏读和不可重复读问题,但是无法彻底解决幻读问题
一个事务执行完之后另外一个事务才能执行,完全服从ACID隔离级别,可以解决脏读、不可重复度、幻读问题
表示一个事务还没有提交,就被另外一个事务读到了。由于未提交的事务可能会回滚,另外一个事务读到的数据就是脏数据
在一个事务中,俩次读取到的结果不一样,因为另外一个事务提交修改了要读取的数据。
不可重复读重点是在修改,同样的条件,多次读取结果不同
幻读重点在于新增和删除:同样的条件,第一次和第二次读出来的记录数不一样

1.读-读:不存在任何问题,也不需要并发控制
2.读-写:存在线程安全问题,可能会造成事务的隔离级别,可能会遇到脏读、幻读、不可重复读
3.写-写:有线程安全问题,可能会造成数据更新丢失问题
1.快照读(普通的select语句):是通过MVCC方式解决幻读问题的,因为再可重复读隔离级别下,事务执行过程中所看到的数据都是事务启动时的数据,即使中途其他是我对数据进行了修改,是查不出该事务的。因为读取的都是其实启动时的数据,所以这就很好避免了幻读问题
2.当前读(select … for update 等语句),是通过next-key lock(记录锁+间隙锁)方式解决了幻读,因为当执行 select … for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
1.使用show processlist 命令查看当前所有连接信息
2.使用explain命令查询SQL语句的执行计划
3.开启慢查询日志,查看慢查询的SQL


优点:有了范式可以减少数据的冗余,数据表更新操作快、占用的内容少
缺点:为了满足三范式会进行分表,查询时通常需要连表查,更难进行索引优化
优点:数据都在一个表中,可以减少表关联,更好进行索引优化
缺点:存在大量的冗余数据,数据的维护成本更高
select id, name from emp where id > 1000000 limit 10;
select id, name from emp where id ( select id from limit 1000000, 1 )limit 10;
select id, name from emp order by limit 1000000, 10;
内连接是在俩个表连表查询的时候,只保留完全匹配的结果集
连表查询的时候,不但保留完全匹配的结果集还有左表中的所有行
连表查询的时候,不但保留完全匹配的结果集还有右表中的所有行
聚合函数自动忽略空值
聚合函数在where之后使用,因为where遍历表的时候聚合函数还有算出来结果那


将多个列组合成一个索引,该索引就被成为联合索引
在InnoDB的存储引擎下,默认的索引结构是B+树结构,也就是说非叶子结点存储的是联合索引,叶子节点,存储的是联合索引和主键
因为联合索引在创建B+树索引的时候,顺序是先按第一个字段排序,如果第一个字段相同再按第二个字段排序。这也就导致了其他字段的顺序依赖于最左边的第一个字段
所以说如果你的where查询条件不是从最左边开始的,就无法使用索引
例如:创建了(a,b,c)的联合索引,你的where 条件 是b c怎么怎么样就无法用到bc索引,因为bc再B+树种是没有顺序的,它依赖于a的顺序
还有就是范围查找后面的字段会索引失效
比如 (a,b,c) where a=1 and b>2 and c = 3;
这种情况就无法使用到了c索引,因为范围查找实际上是按照链表进行遍历,等遍历到b>2的时候,c以及无序了
索引下推是在5.6版本以后引入的,目的是在联合索引遍历的过程中,如果第一个字段相同,那么不用回表找第二个字段,直接在联合索引的B+树种就能判断是否满足条件。
另外,建立联合索引时的字段顺序,对索引效率也有很大影响。越靠前的字段被用于索引过滤的概率越高,实际开发工作中建立联合索引时,要把区分度大的字段排在前面,这样区分度大的字段越有可能被更多的 SQL 使用到。
区分度就是某个字段 column 不同值的个数「除以」表的总行数,计算公式如下:

比如,性别的区分度就很小,不适合建立索引或不适合排在联合索引列的靠前的位置,而 UUID 这类字段就比较适合做索引或排在联合索引列的靠前的位置。
因为如果索引的区分度很小,假设字段的值分布均匀,那么无论搜索哪个值都可能得到一半的数据。在这些情况下,还不如不要索引,因为 MySQL 还有一个查询优化器,查询优化器发现某个值出现在表的数据行中的百分比(惯用的百分比界线是"30%")很高的时候,它一般会忽略索引,进行全表扫描。
对于长度很长的字段如果非要创建索引的话,最好创建前缀索引,就是选该字段的一部分作为索引,但是要保证该部分具有高选择性
覆盖索引二级索引查询查询数据的时候,不用回表就查询到想要的数据的一种现场。
顺序插入可以减少索引的维护代价,而且可以预防页分裂的现象
1.or的左右两边不都是索引
2.where后面的条件是!=这种
3.like ‘%s’ ‘%s%’
假设你建立了name字段的索引,那么name字段作为索引在B+树上的顺序是有序的,但是如果你不是从第一个字母去比较的话,索引就会失效,因为它变得无序了
4.索引列参与计算了
5.索引列放在函数里面了
6.使用联合索引的时候,没有遵循最左前缀原则