数据库面试题

数据库的架构

如何设计一个关系型数据库(数据库的架构)

索引

索引的简介

MySQL 官方对索引的定义为:索引(Index)是帮助 MySQL 高效获取数据的数据结构。

索引的数据结构(B+ 树)

  • B+ 树结构图

  • B+ 树的特点
1.非叶子节点的子树指针与关键字个数相同
2.非叶子节点的子树指针P[i],指向关键字值[K[i],k[i+1])的子树
3.非叶子节点仅用来索引,数据都保存在叶子节点中(查询只在叶子节点结束)
4.所有叶子节点均有一个链指针指向下一个叶子节点(便于数据库的范围统计)
  • B+ 树更适合用来做存储索引的原因
1.B+树的磁盘读写代价更低(树的深度低,IO次数少)
2.B+树的查询效率更加稳定(所有查询结果都会在叶子节点结束)
3.B+树更有利于对数据库的扫描(通过数据指针横向扫描数据)

密集索引和稀疏索引的区别

  • 密集索引文件中的每个搜索码值都对应一个索引值(即可根据索引值找到对应的一条数据,因此每张表只能创建一个密集索引)

  • 稀疏索引文件只为索引码的某些值建立索引项(即根据索引值找到对应一条数据的地址或主键,再根据地址或主键找到数据)

MySQL两种存储引擎的索引区别

参考的博客

  • MyISAM
在MyISAM中不管是主键索引唯一键索引、普通索引,其索引都属于稀疏索引
  • Innodb
在Innodb中 有且仅有一个密集索引 
Innodb中选取规则:
1.如果一个主键被定义了,则该主键作为密集索引
2.若该主键没有被定义,则该表的第一个唯一非空索引作为密集索引
3.若不满足上述条件 则Innodb内部会生成一个隐藏主键(密集索引)
4.非主键索引存储相关键位和其对应的主键值,包含两次查找(第一次根据索引值找到对应数据的主键,然后根据主键找到相应的数据)
  • 两种引擎索引的实例图

  • 两种引擎会建立不同的文件
1.建立一个MyISAM引擎的数据表 test1 会建立三个文件
test1.frm   存储表的结构信息
test1.MYI  存储表的索引信息
test1.MYD 存储表的数据
2.建立一个InnoDB引擎的数据表 test2 会建立两个文件
test2.frm 存储表的结构信息
test2.ibd 存储表的数据和索引

联合索引的最左匹配原则

参考的博客

select * from t where a=1 and b=1 and c =1;     #这样可以利用到定义的索引(a,b,c)

select * from t where a=1 and b=1;     #这样可以利用到定义的索引(a,b,c)

select * from t where a=1;     #这样也可以利用到定义的索引(a,b,c)

select * from t where b=1 and c=1;     #这样不可以利用到定义的索引(a,b,c)

select * from t where a=1 and c=1;     #这样不可以利用到定义的索引(a,b,c)

也就是说通过最左匹配原则你可以定义一个联合索引,但是使得多中查询条件都可以用到该索引。
值得注意的是,当遇到范围查询(>、<、between、like)就会停止匹配。也就是:

select * from t where a=1 and b>1 and c =1;     #这样a,b可以用到(a,b,c),c不可以

总结

  • 在 InnoDB 中联合索引只有先确定了前一个(左侧的值)后,才能确定下一个值。如果有范围查询的话,那么联合索引中使用范围查询的字段后的索引在该条 SQL 中都不会起作用。

  • 值得注意的是,in= 都可以乱序,比如有索引(a,b,c),语句 select * from t where c =1 and a=1 and b=1,这样的语句也可以用到最左匹配,因为 MySQL 中有一个优化器,他会分析 SQL 语句,将其优化成索引可以匹配的形式,即 select * from t where a =1 and a=1 and c=1

索引是建立得越多越好吗

  • 不是
1.数据量小的表不需要建立索引,建立会增加额外的索引开销
2.数据变更需要维护索引,因此更多的索引意味着更多的维护成本
3.更多的索引意味着也需要更多的空间

数据库锁的分类

  • 按锁的粒度划分,可分为表级锁,页级锁,行级锁
  • 按锁级别划分,可分为共享锁(读锁)、排他锁(写锁)
  • 按加锁方式划分,可分为自动锁、显示锁
  • 按操作划分,可分为DML锁、DDL锁
  • 按使用方式划分,可分为乐观锁、悲观锁

MySQL两种存储引擎的锁区别

1.MyISAM默认用的表级锁,不支持行级锁
2.InnoDB默认用的是行级锁,也支持表级锁

注意

当InnoDB做增删改查的数据没用到索引时,会上表级锁,否则默认上的是行级锁

数据课事务的四大特性

ACID

  • 原子性(Atomic)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

事务隔离级别及对应解决的并发问题

  • 更新丢失——MySQL所有事务隔离级别在数据库层面上均可避免

  • 脏读——READ-COMMITTED 事务隔离级别以上可避免(oracle默认的事务隔离级别)

    脏读解释:一个事务读到了另一个尚未提交的事务更改后的数据
    
  • 不可重复读 ——REPEATABLE-READ事务隔离级别以上可避免(MySQL默认的事务隔离级别)

    不可重复读解释:一个事务重复读同一数据时,数据不一致
    
  • 幻读——SERIALIZABLE事务隔离级别可避免

    幻读解释:一个事务进行更新时,有另外一个事务进行了增加或删除操作并提交了,导致原本更新的行数增加了或减少了
    

InnoDB可重复读隔离级别下如何避免幻读

使用next-key锁(行锁+gap锁)

gap锁的解释:也叫范围锁,会锁定一个范围,但不包括记录本身。当一个范围被gap锁锁住时,无法往这个范围进行写操作(增删改)。

只有在隔离级别REPEATABLE-READ和SERIALIZABLE的时候才会使用gap锁,低于隔离级别REPEATABLE-READ不会使用gap锁

gap锁的使用情况

  1. 当使用唯一索引或主键索引时

    • 如果where条件全部命中,则不会使用gap锁,只会加行级锁

      #id为主键或为唯一键
      delete into tbl_name where id=1;
      #此时不会使用gap锁,因为该记录是唯一的,不会因为别的事务增加一条id=1记录(唯一键约束无法增加),造成幻读
      
    • 如何where条件部分命中或者全不命中,则会加gap锁

      #id为主键或为唯一键,但记录中没有id=2的数据,有id=1,id=3的数据
      delete into tbl_name where id=2;
      #此时会使用gap锁,gap锁的范围会是id的值:1<被锁的范围<=3,在这个范围另一个无法进行写操作,从而避免幻读了
      
  2. 当使用非唯一索引或者不走索引时

    • 非唯一索引

      #id为非唯一索引,有id=1,id=2,id=3的数据
      delete into tbl_name where id=2;
      #此时会使用gap锁,gap锁的范围会是id的值:1<被锁的范围<=3(因为id=2的记录不是唯一的)
       ,在这个范围另一个无法进行写操作,从而避免幻读了
      
    • 不走索引

      #id该字段没有索引,有id=1,id=2,id=3的数据
      delete into tbl_name where id=2;
      #此时会使用gap锁,gap锁的范围会是整张表,因为不走索引无法确定id=2具体在哪个范围
      

    关于group by与having

    group by的语法

    1.group by里出现某个表的字段,select里面的列要么是该group by里出现的列,要么是别的表或者带有列函数的列
    2.列函数形如:count(),sum(),max()等统计函数,列函数对于group by子句定义的每个组各返回一个结果

    #查询所有同学的学号(group by 出现的字段)、姓名(别的表的字段)、
    选课数(带有列函数的列)、总成绩(带有列函数的列)
    select s.student_id,stu.name,count(s.course_id),sum(s.score)
    from 
    	score s,
    	student stu
    where
    s.student_id=stu.student_id
    group by student_id;
    

    having的语法

    1. 通常与group by子句一起使用
    2. where过滤行,having过滤组
    3. 出现在同一sql的顺序:where>group by>having
    #查询没有学全所有课的同学的学号、姓名
    select s.student_id,stu.name
    from 
    	score s,
    	student sut
    where s.student_id=stu.student_id
    group by s.student_id
    having count(s.score_id)<
    (select s.score_id from s);
    

    三大范式

    参考的博客

    三大范式通俗解释:

    (1)简单归纳:

      第一范式(1NF):字段不可分;
      第二范式(2NF):有主键,非主键字段依赖主键;
      第三范式(3NF):非主键字段不能相互依赖。

    (2)解释:

      1NF:原子性。 字段不可再分,否则就不是关系数据库;;
      2NF:唯一性 。一个表只说明一个事物;
      3NF:每列都与主键有直接关系,不存在传递依赖。

原文地址:https://www.cnblogs.com/shouyaya/p/13478716.html