MySQL索引常见问题

索引的优缺点是什么?

没有索引的话操作系统会把所有的数据加载到内存依次进行检索,加载的数据很多IO次数也会很多,有了索引只会加载某个列或者主键id,IO的次数就会比较少,速度就会比较快,提升了数据库的效率,缺点就是索引需要占用空间以空间换时间来提升效率的,创建和维护索引要耗费时间这个时间随着数据量的增加而增加。

聚簇索引和非聚簇索引

  • 聚簇索引:
  1. 将数据存储在索引树的叶子节点上,查询索引树的时候可以直接获取到数据减少了回表的一次查询
  2. 聚簇索引的缺点是在修改或者删除操作的时候需要更新索引树,会增加系统的开销
  3. 主要用于提高查询的效率
  • 非聚簇索引(辅助索引):
  1. 数据不会存放在索引树的叶子节点上,而是存储在数据页中
  2. 通常查询数据需要两次查询,一次查找索引树获取数据页的地址,第二次通过页地址查询数据(索引覆盖不需要回表
  3. 在修改或者删除数据操作的时候不需要修改索引树,减少了系统的开销
  4. 主要用于提高更新和删除操作的效率

hash索引

  • 通过hash算法计算索引列中的全部内容作为key,将这条数据的行地址作为value一并存到hash表中的对应位置
  • 在MySQL中只有Memeory支持哈希索引
  • 不支持部分索引列的匹配查找,比如给数据列(A,B)建立索引,因为它是根据索引列的全部内容来计算哈希值的,所以如果查询只有数据列A,则无法使用该索引
  • 不支持范围查找,不可能把范围里面的每一个关键字都拉出来算他的索引值去查找
  • 精准查询效率很高接近于O(1),但是有哈希冲突问题,如果出现哈希冲突问题存储引擎必须遍历链表中的所有数据,逐个比较代价很大

什么是唯一索引

  • 确保写入数据库的数据具有唯一性
  • 如何只在业务中做校验,可能在数据库中会出现脏数据
  • 可以为空

联合索引

  • 使用函数、会出现索引失效
  • 联合索引最左匹配原则:(A,B)联合索引,查询中只要包含A,B不管顺序如何都会走索引,如果还有别的未建立索引的字段会进行回表查找,性能会降低,但如果没有A只有B则不会走索引,因为索引树是先给A排序之后再给B排序,直接查找B是乱序
  • 模糊匹配如果是%sql%这种形式会出现索引失效,因为一开始都不确定是什么的话索引就不会生效,sql%这种模糊查询是会走索引的

使用索引一定能提升效率吗?

不一定

  • 对于查询使用少的字段不建议建索引,占用空间增删改效率降低

InnoDB和MyISAM的索引有什么区别

都是B+树实现的

  • InnoDB使用的是聚簇索引,MyISAM使用的是非聚簇索引
  • InnoDB支持事务,外键,MyISAM不支持
  • InnoDB支持行级锁,MyISAM不支持行级锁只支持表级锁
  • InnoDB支持数据库异常崩溃后的安全恢复

什么是索引下推

针对MySQL5.6扫描二级索引的一项优化,本来一些过滤条件是在MySQL服务层去做的,现在在匹配索引的时候就加上这些过滤的条件,将索引过滤的条件下推到引擎层来降低回表的次数

哪些情况会导致索引失效

  1. 全值匹配 ,对索引中所有列都指定具体值。该情况下,索引生效,执行效率高,但需要回表。
explain select * from tb_seller where name='小米科技' and status='1' and address='北京市';


2. 最左前缀法则
如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始,并且不跳过索引中的列。

匹配最左前缀法则,走索引:
在这里插入图片描述
违法最左前缀法则 , 索引失效:
在这里插入图片描述
如果符合最左法则,但是出现跳跃某一列,只有最左列索引生效:
在这里插入图片描述

  1. 范围查询右边的列,不能使用索引 。
    在这里插入图片描述
    根据前面的两个字段name , status 查询是走索引的, 但是最后一个条件address 没有用到索引。

  2. 不要在索引列上进行运算操作, 索引将失效。
    在这里插入图片描述

  3. 字符串不加单引号,造成索引失效。
    在这里插入图片描述
    由于,在查询是,没有对字符串加单引号,MySQL的查询优化器,会自动的进行类型转换,造成索引失效。

6). 尽量使用覆盖索引,避免select *

尽量使用覆盖索引(只访问索引的查询(索引列完全包含查询列)),减少select * 。
在这里插入图片描述
如果查询列,超出索引列,也会降低性能。
在这里插入图片描述
TIP :

using index :使用覆盖索引的时候就会出现

using where:在查找使用索引的情况下,需要回表去查询所需的数据

using index condition:查找使用了索引,但是需要回表查询数据

using index ; using where:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据
  1. 用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
    示例,name字段是索引列 , 而createtime不是索引列,中间是or进行连接是不走索引的。

  2. 以%开头的Like模糊查询,索引失效。
    如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。
    在这里插入图片描述
    解决方案 :
    通过覆盖索引来解决
    在这里插入图片描述

  3. 如果MySQL评估使用索引比全表更慢,则不使用索引。
    在这里插入图片描述

  4. is NULL , is NOT NULL 有时索引失效。
    在这里插入图片描述

  5. in 走索引, not in 索引失效。
    在这里插入图片描述

  6. 单列索引和复合索引。

尽量使用复合索引,而少使用单列索引 。

创建复合索引

create index idx_name_sta_address on tb_seller(name, status, address);

就相当于创建了三个索引 :
name
name + status
name + status + address
创建单列索引

create index idx_seller_name on tb_seller(name);
create index idx_seller_status on tb_seller(status);
create index idx_seller_address on tb_seller(address);

数据库会选择一个最优的索引(辨识度最高索引)来使用,并不会使用全部索引 。
13. 使用order by可能导致索引失效

使用order By能否通过索引排序?

不一定,有三种情况

  • 第一种情况:建立了一个索引,根据这个索引字段order by进行排序,但是where后面没有这个条件,这时是不会走索引的,因为sql执行的顺序是先根据where后面的查询条件得到数据,之后再根据order by去排序,会看根据where后面的查询条件查找数据的时候有没有用到索引,如果用到了索引那么order by直接获取索引的顺序就不用自己去排序了,如果没有用到就不会走索引
  • 第二种情况:where后面有order by排序的这个字段,那么会走索引,order by直接获取索引的顺序就不用自己去排序了
  • 第三种情况:查询的字段也建了索引值,他直接会走二级索引并且不用回表,因为查询的字段在索引树里面都存在,就不用再根据主键值再去回表查别的字段了

B树和B+树的区别

  • B树的每个节点上都会存数据,B+树只有叶子节点会存数据
  • B+树叶子节点之间有指针连接,B树没有
  • 在查询的时候,B树相当于对范围内的每个关键词做二分查找,可能还没有查询到叶子节点,查询就结束了,查询效率比较低并且不稳定,而B+树做查询的时候是先遍历到索引树的叶子节点,通过叶子节点之间的指针做顺序查找,所以效率比较高也更稳定

数据库表设计时,字段应该如何选择

  1. 字段类型优先级
    char:定长
    varchar:不定长
    char>varchar
  2. 可以选择整型就不选字符串,整型排序快一些
  3. 够用就行不要慷慨:大的内存影响速度
  4. 尽量避免使用null,null不利于索引也不利于查询
  5. char和varchar:char长度固定,处理速度要比varchar快很多,但是比较费内存空间,在速度上有要求可以使用char类型

MySQL中varchar(M)最多能存储多少数据?

65535个字节,除了blob和text类型的列之外,其他所有的列占用的字节长度加起来不超过65535

事务的四个特性

  • 原子性:一个事务中的操作要么全部成功,要么全部失败
  • 一致性:数据前后的总额是相等的
  • 隔离性:一个事务在修改未提交之前其他事务锁不可见的
  • 持久性:一个事务一旦提交,所做的修改会永久保存到数据库中

事务隔离级别

  • 读未提交:最低的隔离级别,允许读取未提交的数据,有脏读、幻读、不可重复读的问题。
  • 读已提交:允许读取已经提交的数据,可以阻止脏读,有幻读、不可重复读的问题。
  • 可重复读:对同一字段多次读取的结果是一致的,可以阻止脏读,不可重复读的问题,但是幻读仍有可能发生。
  • 可串行化:最高的隔离级别,所有事务逐个进行,事务之间完全不会产生干扰,可以防止脏读、幻读、不可重复读的问题。

不可重复读和幻读有什么区别?

不可重复读关注的是在两次相同的查询之间,数据是否发生了变化;而幻读关注的是在两次相同的查询之间,是否有新的数据被插入。

脏读的解决

InnoDB会给每行数据增加一个事务id,当一个事务开始的时候会获取一个唯一的事务id,当一个事务读取一行数据的时候,innoDB会检查这个数据的事务id是否小于当前事务的id,如果小于说明这是已经提交的数据,如果大于说明这个数据还没被提交,innoDB将阻止该事务读取改行数据。

不可重复读的解决

在可重复读隔离级别下,通过MVCC来解决,当使用快照读进行读取的时候只有第一次读取的时候会生成一个Read View,对比Read View中的事务id和undolog中快照的事务id,选择快照,后续所有的快照读都是用同一个快照,所以就不会发生不可重复读的问题了。

Read View

还未提交的事务id数组

幻读的解决

临键锁(记录锁+间隙锁):左开右闭,锁住一段范围
间隙锁:开区间,锁住一段范围
在读已提交隔离级别下,通过临键锁来解决。

快照读和当前读

快照读:就是读取的是当前快照生成的那一刻的数据,select语句就是快照读
当前读:读的是最新的数据,给select加锁还有一些增删改会进行当前读

这些快照数据放到undo log中,一条记录的多个快照会用指针给他连起来形成一个快照链表

事务并发可能造成什么问题?

  • 脏读:读取到另外一个事务未提交的数据的现象
  • 不可重复读:前后两次读取的数据出现了不一致
  • 幻读:读取同一个范围的数据,在事务B两次读取的过程中事务A插入了数据,导致事务B后一次读取到了第一次没有查询到的行

MySQL各种索引

单列索引:

  1. 主键索引:建立在主键上的索引,一张表只能有一个主键索引不能为空
  2. 唯一索引:一张表可以有多个唯一索引,运行为null,列表中出现多个空值不会发生重复冲突在主键上的索引
  3. 普通索引:在普通字段上建立的索引

组合索引:相当于创建了多个索引,一般把最常用的放在最左边
create index index3 on demo(col1,col2,col3)
相当于创建了col1,col1+col2,col1+col3,col1+col2+col3

全文索引(fulltext):只能在char,varchar,text等字段才能使用全文索引,全文索引是抽取到一列内容的关键字,然后通过关键字建立索引。相当于含like的模糊查询。

InnoDB一颗B+树key存放约2000万行数据

如何提高insert的性能

  1. 合并多条insert为一条:日志会减少很多

全局锁、共享锁、排他锁

  • 全局锁:对整个数据库加锁,使整个库处于可读的状态,之后更新语句会被阻塞
  • 共享锁(读锁):读取操作创建的锁,只能读取数据但是不能修改,直到已释放所有的共享锁,
  • 排他锁(写锁):在事务的某一行加上了排他锁,只有这个事务可以对其进行读写,其他事务都不能进行读和写的操作,知道这个锁被释放,它是悲观锁的一种实现。

谈一下MySQL中的死锁

死锁是两个或者两个以上的进程在执行过程中,手中拥有其他进程需要的资源,并且持续请求自己需要的资源也不放手自己手中的资源,形成一种相互等待的局面,这就是死锁

  • 如何查看死锁:通过命令show engine innodb status
  • 对待死锁的两种策略:
  1. 设置超时时间,超时之后对应的资源就会被释放。
  2. 发起死锁检测,发现死锁之后主动回滚死锁中的某一个事务让其他事务继续执行。

MySQL的锁类型有哪些

  • 基于锁的级别分类
  1. 共享锁:又叫读锁,读数据时不允许其他事务对其进行修改但是可以查询,sql语句是lock in share mode
  2. 排他锁:又叫独占锁,一个事务加了写锁,其他的事务既不能读也不能写,也不能加锁,sql语句是for update。他是基于悲观锁的一种实现,增删改会自动增加排它锁
  • 锁的粒度
  1. 表级锁:上锁的时候锁的是整个表,其他的事务不能访问这个表,必须要等锁释放了之后才能访问,粒度大,容易冲突
  2. 行级锁: 对一行或者多行上锁,其他事务不能访问这些行,粒度小,不容易冲突
  3. 记录锁:只会锁一行记录
  • 锁的状态
    意向锁:一个事务在表里加了一个排他锁,那就不允许其他事务再加排他锁和共享锁了,后面的事务需要获取一个状态知道自己能不能对表加锁,避免了对索引树的每个结点进行扫描是否加锁,这个状态就是意向锁。

MyISAM表锁

在这里插入图片描述
MyISAM 在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁。

  • 一个事务给一个表上了读锁,其他事务可以读但是不能写,该事务也只能读这张表的数据不能对其他表做操作,直到commit提交后释放锁。
  • 一个事务给一个表上了写锁,其他事务不能对该表进行读和写操作,直到commit提交后释放锁。
  • 此外,MyISAM 的读写锁调度是写优先,这也是MyISAM不适合做写为主的表的存储引擎的原因。因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。MyISAM适合读多写少。

InnoDB行锁

对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);
对于普通SELECT语句,InnoDB不会加任何锁;
在这里插入图片描述
在这里插入图片描述

  • 如果不通过索引条件检索数据(无索引或索引失效),那么InnoDB将对表中的所有记录加锁,实际效果跟表锁一样。
  • 当我们用范围条件,而不是使用相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据进行加锁(间隙锁); 对于键值在条件范围内但并不存在的记录,叫做 “间隙(GAP)”
    在这里插入图片描述

如何进行sql优化

  1. 基本写法优化
  • 少用select *
  • 条件的类型要写对,像字符串不加单引号索引就会失效
  • 少用order by排序,因为order by它可能走索引也可能不走索引,一般分为三种情况,第一种情况锁给order by修饰的字段建立索引之后,where后面没有查询这个字段那就会索引失效,会进行全表查询,第二种情况锁where后面有这个字段的查询条件,因为索引底层B+树它本身就是有序的,所以根据where条件查询后的数据排序的时候会直接根据B+树的顺序就不用order by自己再去排序了,第三种情况是查询的字段就是你建立索引的那个字段,那就是覆盖索引,可以直接查二级索引树不用回表,这种情况索引也是生效的,所以如果必须要用到order by排序可以在where条件里面加上这个字段的条件,这样就可以走索引了
  • 查询时候少用null,因为null不利于索引也不利于查询
  • 少用like,如果要用尽量用like%,不然会造成索引失效
  • 少用函数,函数也会造成索引失效
  1. 建立合适的索引
  • 对高频筛选的字段建立索引
  • 一个表的索引最好不要超过五个,多了会影响插入修改
  • 使用联合索引遵循最左原则
  1. 代替优化
  • 不要使用not in 和不等于,这个会破坏索引,not in 可以用not exist 代替,不等于可以分成两个条件,>或者<
  • 在sql里面尽量少使用子查询可以连表来代替子查询

4、数据库表的设计

MySQL支持的表连接类型有几种

  • 内连接:inner join查出来的就是两个表能关联到的数据
  • 左连接:left join 查出来是关联到的数据和左表的数据
  • 右连接:right join查出来是关联到的数据和右表的数据

count(*),count(列),count(1)区别

count(列)是统计列中包含多少数据不含NULL值
表中有索引列count(*)更快,这三个性能差不多

优化sql步骤

  1. 查看sql执行频率
    在这里插入图片描述
  2. 定位低效率执行sql
  • 慢查询日志:查询结束后,通过慢查询日志定位那些执行效率较低的sql语句
  • show processlist:查看实时sql语句执行情况,实时定位到慢sql
    在这里插入图片描述
  1. explain分析执行计划
  • id id表示操作表的顺序,
    (1)id相同 表示从上至下依次执行
    (2)id不同 id越大优先级越高,越先被执行
  • select_type 表示select的类型
    在这里插入图片描述
  • table 表示查询的哪张表
  • type 访问类型(越往上执行速度越快)
    在这里插入图片描述
    一般来说,我们需要保证查询至少达到range级别,最好到ref
  • key
    (1)possible_key:可能走的索引
    (2)key:实际走的索引
    (3)key_len:索引长度(越短越好)
  • rows 扫描行的数量
  • extra 额外信息
    在这里插入图片描述
    优化前两个
  1. show profile查询每个阶段的用时在这里插入图片描述
  2. trace分析优化器执行计划
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值