面试笔记 — Mysql

1.MySQL主键索引和普通索引的区别?

  •    主键索引索引着数据,然后普通索引索引着主键ID值(这是在innodb中,但是如果是myisam中,主键索引和普通索引是没有区别的都是直接索引着数据)
  •     当你查询用的是where id=x 时,那只需要扫描一遍主键索引,然后拿到相应数据 .但是如果是查询的普通索引的话,那么会先扫描一次普通索引,拿到主键值,然后再去扫主键索引,拿到所需要的数据,这个过程叫做回表

2.索引页和数据页

     索引信息(其它也是一行一行的记录)存储在索引页上(只存储数据记录中的索引字段值以及字段值与所在记录行地址的对应关系,相对要窄一些),

     数据记录存储于数据页上(存储数据记录中的每一个字段值,相对要较宽一些),索引页小,不过是因为它只保存每条记录的这一字段,所以会小,如果数据表只有一列,那索引页和数据页的大小将会是相同的;

3.B+树

   B+树形式存储(B树是二叉树,B-树是3节点多路查找树,B+树让叶子节点指向相邻的其它叶子上的节点

   B+树的非叶子节点并不直接存储可以从磁盘中取出关键值的指针,而是存储关键值的索引,关键值只存储在叶子节点中,并且叶子节点组成了一个有序链表。由于节点并不存储关键值的数据指针,所以节点的比较不需要IO操作,顺着指针找到叶子节点,并根据叶子节点的数据指针进行一次IO操作,取出完整数据,查找完成。

面试笔记 — Mysql_第1张图片

3.聚集索引和非聚集索引

          聚集索引:设置目录的排序方式和数据直接对应。(字典的拼音目录,正文就是按照页码顺序排列的)   

       非聚集索引:字典的偏旁部首,页码是散开的,最终结果只是逻辑上的连续。

  1) 区别

  • 聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个
  • 聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续
  • 聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序。
  • 非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序。
  • 索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据

 2)优势与缺点:

       聚集索引插入数据时速度要慢(时间花费在“物理存储的排序”上,也就是首先要找到位置然后插入),查询数据比非聚集数据的速度快。

 3)是不是聚集索引就一定要比非聚集索引性能优呢?
  
       如果想查询学分在60-90之间的学生的学分以及姓名,在学分上创建聚集索引是否是最优的呢?

       否。既然只输出两列,我们可以在学分以及学生姓名上创建联合非聚集索引,此时的索引就形成了覆盖索引,即索引所存储的内容就是最终输出的数据,这种索引在比以学分为聚集索引做查询性能更好
 

 4)在主键是创建聚集索引的表在数据插入上为什么比主键上创建非聚集索引表速度要慢?

       在有主键的表中插入数据行,由于有主键唯一性的约束,所以需要保证插入的数据没有重复。我们来比较下主键为聚集索引和非聚集索引的查找情况:聚集索引由于索引叶节点就是数据页,所以如果想检查主键的唯一性,需要遍历所有 数据节点才行。但非聚集索引,只需要遍历所有的索引页就行(索引的存储空间比实际数据要少),这比遍历所有数据行减少了不少IO消耗。
 

4.事务隔离级别

   MySQL默认(repeatable-read)   PostgreSQL、QL server 、oracle中 数据库的默认隔离级别 是read-committed,

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted)
读已提交(read-committed)
可重复读(repeatable-read)
串行化(serializable)

    1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

  2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

  3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

  小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

5.MYSQL的存储引擎

  MyISAM:       

  • 不支持事务
  • 表级锁定:数据更新时锁定整个表:其锁定机制是表级锁定,也就是对表中的一个数据进行操作都会将这个表锁定,读写互相阻塞:不仅会在写入的时候阻塞读取,MyISAM还会再读取的时候阻塞写入,但读本身并不会阻塞另外的读。
  • 只会缓存索引:MyISAM可以通过key_buffer_size的值来提高缓存索引,以大大提高访问性能减少磁盘IO,但是这个缓存区只会缓存索引,而不会缓存数据。
  • 读取速度较快:占用资源相对较少
  • 不支持外键约束,但支持全文索引
  • MyISAM 引擎主健索引和普通索引在结构上没有任何区别,只是主键索引要求 key 是唯一的,而辅助索引的 key 可以重复。都使用 B+Tree 作为索引结构,叶节点的 data 域存放的是索引表,普通索引叶节点的 存放的是主键的地址。

          面试笔记 — Mysql_第2张图片

 InnoDB引擎:

  • 支持事务
  • 行级锁定(更新时一般是锁定当前行):通过索引实现,全表扫描仍然会是表锁,注意间隙锁的影响。
  • 读写阻塞与事务隔离级别相关。
  • 具体非常高效的缓存特性:能缓存索引,也能缓存数据。
  • 支持分区,表空间,类似oracle数据库。
  • 支持外键约束,不支持全文索引(5.5之前),以后的都支持了。
  • 主索引叶节点的 data 域存放的是数据表,辅助索引 data 域存储相应记录主键的值而不是地址,需要通过主键值回表拿到数据值

面试笔记 — Mysql_第3张图片

 如果希望以最节约空间和时间或者响应速度快的方式来管理数据表,MyISAM数据表就应该是首选.如果应用程序需要用到事务,使用外键或需要更高的安全性,以及需要允许     
 

、数据库优化

  当数据库遇到瓶颈,比如高并发情况下连接数不够;数据量太大;因存储问题,数据库所在机器性能下降。就需要进行优化,一把安装以下思路进行

    1.SQL与索引:检查自己的慢SQL,进行优化,用到索引

    2.表和存储引擎:优化表设计,对于字段类型和长度的选择,看表结构是否需要拆分或合并,不同的表需要选择什么存储引擎,是不是需要分区等

    3.架构:(1)数据是在磁盘存储,如果加了索引还是很慢,可以部署缓存服务器,把数据在内存里缓存起来。

                  (2)如果一台数据库服务器承受不了访问压力,可以部署集群做负载均衡。当然数据库节点应有自动同步机制。

                  (3)有了主从同步后,就可以主从复制实现读写分离。让写的服务都访问master服务,读的请求都访问从服务器

                  (4)读写分离后还存在两个问题: a.只有一个master,写的压力没有分摊; b.所有节点存储数据相同,在一个节点出现瓶颈的时候,其他节点一样遇到相同问题。

                           此时需要分片即分库分表,对每个节点都只存储总体数据的一部分。分片后为了提升可用性再对分片做冗余

    4.数据库配置:(1)机器虽然配置很高了,但性能没有发挥到极致,还可以优化数据库配置(连接数、缓冲区大小等)

    5.操作系统和硬件

   
三、SQL优化一般步骤

    1、通过慢查日志等定位那些执行效率较低的SQL语句

#查看开启状态和日志位置
SHOW VARIABLES like '%slow_query_log%'


#开启(只对当前数据库本次有效)
set global slow_query_log =1

#查看阈值
SHOW VARIABLES like '%slow_query_time%'

#设置阈值
set global slow_query_time =3

#查看慢sql的统计
SHOW global status like '%slow_query%'

      mysqldumpslow: 该工具是慢查询自带的分析慢查询工具,一般只要安装了mysql,就会有该工具;常用的命令如下

mysqldumpslow -s c -t 10 /var/run/mysqld/mysqld-slow.log # 取出使用最多的10条慢查询

mysqldumpslow -s t -t 3 /var/run/mysqld/mysqld-slow.log # 取出查询时间最慢的3条慢查询

mysqldumpslow -s t -t 10 -g “left join” /database/mysql/slow-log # 得到按照时间排序的前10条里面含有左连接的查询语句

 mysqldumpslow -s r -t 10 -g 'left join' /var/run/mysqld/mysqld-slow.log # 按照扫描行数最多的

2、explain 分析SQL的执行计划

          :1).表的读取顺序(id) : 相同按顺序执行,不同id越大优先级越高)     

           2).数据读取的操作类型(select_type)::simple:普通查询; primary:主查询; subquery:子查询; derived 衍生出临时表;  union:union之后的select;   union_result: 从union获取结果

           4) 那些索引可以使用(possible_keys)   

           5)那些索引被实际使用(key)   

           6).索引的哪一行被引用

           7).每张表有多少行被优化器查询(row)

           8) type类型(由上至下,效率越来越高

ALL 全表扫描
index 索引全扫描
range 索引范围扫描,常用语<,<=,>=,between,in等操作
ref 使用非唯一索引扫描或唯一索引前缀扫描,返回单条记录,常出现在关联查询中
eq_ref 类似ref,区别在于使用的是唯一索引,使用主键的关联查询
const 单条记录,通过唯一索引一次 找到
system 单表且一行记录 

       9) Extra:额外信息

Using filesort  (需避免) 文件排序(mysql 中无法利用索引排序
Using temporary(需避免) 使用了临时表保存中间结果(常见于排序和分组查询,索引错乱时
Using index  (效率高)

 select 操作中使用了覆盖索引(查询的数据列全部建有索引),避免访问了表的数据行。

 如果同时出现 using where,意味着无法直接通过索引查找来查询到符合条件的数据,该索引被用来执行索引值的查找。  如果没有出现表示索引用来读取数据而非执行查找动作

using where  表明使用了where过滤
using join buffer 使用了连接缓存
impossible where where 字句的值总是false

3、show profile 分析

了解SQL执行的线程的状态及消耗的时间。默认是关闭的,开启语句“set profiling = 1;”

#查看状态
SHOW VARIABLES like 'profiling' 

#开启
set profiling = on

#查看结果(系统上运行的sql分析结果)
show profiles;

#诊断sql
show PROFILE for QUERY  #{上一步sql编号};

4、trace

trace分析优化器如何选择执行计划,通过trace文件能够进一步了解为什么优先选择A执行计划而不选择B执行计划。

set optimizer_trace="enabled=on";
set optimizer_trace_max_mem_size=1000000;
select * from information_schema.optimizer_trace;

5、确定问题并采用相应的措施

 1)优化索引,防止失效

  • 最佳做前缀原则:使用复合索引时,查询和排序从索引的最左列开始并且不跳过中间索引的列(中间断掉,后面的索引不再被使用。条件and的顺序会被自动优化,但建议按顺序写)
  • 不要在索引列上做操作,会导致全表扫描
  • 范围之后 索引失效,
  • 尽量少用selelct *,使用覆盖索引
  • 使用 !=  、 > 、 < 、is null、 is not null 的时候无法使用索引会导致全表扫描
  • like 以通配符开头索引失效
  • mysql内部进行了类型转换  (比如字符串不加单引号) 索引失效
  • 使用or 连接导致索引失效

   总结:带头大哥不能死,中间兄弟不能断,索引列上无操作,like%加右边,范围之后全失效,字符串里有引号,索引覆盖我最爱

2)优化SQL语句:修改SQL、IN 查询分段、时间查询分段、基于上一次数据过滤

  • 永远小表驱动大表(嵌套循环查询,先查小表,再用小表去匹配外表)
  •  order by 排序中索引的顺序必须和预定义一样。
  • 查询where中的索引使用顺序可以该表,只要带头大哥在就不会产生全表扫描
  • Group by 先排序后分组,遵循索引健的最佳左前缀。
  • where 高于having,能在where限定就不要去having限定

 3)改用其他实现方式:ES、数仓等

 4)数据碎片处理

你可能感兴趣的:(面试知识点)