整理了一下数据库在面试中的常问点。
数据库保护(数据库控制)的四种方式:
- 完全性控制
- 完整性控制
- 并发性控制
- 数据恢复
数据库索引的作用及优缺点
索引的原理大致可以概括为空间换时间。数据库在未添加索引的时候,进行查询默认进行的是全表搜索,也就是有多少条记录就会进行多少次查询。假如一张表有一亿条数据 ,需要查找其中某一条数据,按照常规逻辑, 一条一条的去匹配的话, 最坏的情况下需要匹配一亿次才能得到结果,最坏时间复杂度就是O(n),这是无法接受的,而且这一亿条数据显然不能一次性读入内存供程序使用。因此引入了索引。
一条索引记录中包含的基本信息包括:键值+逻辑指针(指向数据页或者另一索引页)
优点:
- 数据库索引可以加快数据的查询速度
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性
- 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义
缺点:
索引能让数据库查询数据的速度上升, 而使写入数据的速度下降,增删改数据都会改变B树各节点中的索引数据内容,因此数据的维护速度变慢
创建索引和维护索引需耗费时间
- 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大
- 对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度
数据结构:基于B树或者B+树。
聚集索引
非聚集索引
聚集索引 VS 非聚集索引
通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据。
- 聚集索引:在索引表上逻辑相邻的记录,在物理位置上也相邻
- 非聚集索引:索引的逻辑顺序与磁盘上记录的物理存储顺序不同
一个很形象的例子来说明聚集索引和非聚集索引的区别。
- 聚集索引类似于我们根据汉字拼音在汉语字典中查询某个字。“安”的拼音是“an”,而按照拼音排序,汉语字典是以英文字母“a”开头并以“z”结尾的,那么“安”字就自然地排在字典的前部。在拼音表中,“安”的下一个字“按”的拼音也是“an”,在字典中的顺序也排在“安”的下一个字。这种逻辑顺序与物理顺序一致的索引,为聚集索引
- 非聚集索引类似于我们根据偏旁部首在汉语字典中查询某个字。比如您查“张”字,我们可以看到在查部首之后的检字表中“张”的页码是672页,检字表中“张”的上面是“驰”字,但页码却是63页,“张”的下面是“弩”字,页面是390页。很显然,这些字并不是真正的分别位于“张”字的上下方。这种索引方式需要两个过程,先找到目录中的结果,然后再翻到您所需要的页码。
何时使用聚集索引或非聚集索引
| 动作描述 | 使用聚集索引 | 使用非聚集索引 |
| :—————– | ———— | ————– |
| 列经常被分组排序 | 应 | 应 |
| 返回某范围内的数据 | 应 | 不应 |
| 一个或极少不同值 | 不应 | 不应 |
| 小数目的不同值 | 应 | 不应 |
| 大数目的不同值 | 不应 | 应 |
| 频繁更新的列 | 不应 | 应 |
| 外键列 | 应 | 应 |
| 主键列 | 应 | 应 |
| 频繁修改索引列 | 不应 | 应 |
数据库事务的四大特性:
- 原子性:一个事务(Transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性:一个事务执行之前和执行之后都必须处于一致性状态。拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
- 隔离性:当两个或者多个事务并发访问(此处访问指查询和修改的操作)数据库的同一数据时所表现出的互相关系。级别一般有:Read Uncommitted,Read Committed,Repeated Read,Serializable。
- 持久性:一个事务一旦被提交了,那么对数据库中数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
数据库事物隔离级别
- 读未提交(Read Uncommitted)
- 允许脏读,其隔离级别是最低的。
- 脏读:一个事务处理过程里读取了另一个未提交的事务中的数据,如果这些数据被回滚,则读到的数据是无效的。
- 读已提交(Read Committed)
- 不会出现脏读的情况,但允许不可重复读
- 不同执行的时候只能获取到已经提交的数据
- 不可重复读:在同一个事务中,读到另一个事务已经提交更新的数据
- 可重复读(Repeated Read)
- 保证在事务处理过程中,多次读取同一个数据时,该数据的值和事务开始时刻是一致的
- MySQL的默认事务隔离级别是Repeated Read
- 串行读(Serializable)
- 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
| 事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
| —————————- | —- | ———- | —- |
| 读未提交(Read Uncommitted) | 允许 | 允许 | 允许 |
| 读已提交(Read Committed) | 禁止 | 允许 | 允许 |
| 可重复读(Repeated Read) | 禁止 | 禁止 | 允许 |
| 串行读(Serializable) | 禁止 | 禁止 | 禁止 |- 读未提交(Read Uncommitted)
数据库的三大范式
第一范式(确保每列保持原子性)
确保数据库表中的每一列是不可分解的原子值。
比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。
第二范式(确保表中的每列都和主键相关)
比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下表所示。
这样就产生一个问题:这个表中是以订单编号和商品编号作为联合主键。这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品编号相关。所以在这里违反了第二范式的设计原则。
把这个订单信息表进行拆分,把商品信息分离到另一个表中,把订单项目表也分离到另一个表中,则满足了第二范式。
第三范式(确保每列都和主键列直接相关,而不是间接相关)
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。如下面这两个表所示的设计就是一个满足第三范式的数据库表。
MongoDB和MySQL的区别
NoSQL的分类:
- 键值型数据库——Redis
- 文档型数据库——MongoDB
- 列存储数据库——HBase
- 图形数据库
NoSQL的使用情况:
- 对数据的存储灵活性要求高,一致性要求低
- 数据处理海量并发,要求瞬间效率速度比较高
- 数据比较容易建立Nosql模型
- 网站临时缓冲存储,爬虫应用
常见的关系型数据库有:Oracle、DB2、Microsoft SQL Server、Microsoft Access、MySQL等
关系型数据库的优点:
- 保持数据的一致性(事务处理)
- 由于以标准化为前提,数据更新的开销很小(相同的字段基本上都只有一处)
- 可以进行Join等复杂查询
MySQL(关系型数据库) 和 MongoDB(非关系型数据库)的概念对比
| MySQL | MongoDB | 含义 |
| ——– | ———- | ——— |
| database | database | 数据库 |
| table | collection | 表/集合 |
| column | filed | 字段/域 |
| row | document | 记录/文档 |关系型数据库 VS 非关系型数据库
关系型数据库(SQLite、Oracle、mysql)
特性:
- 关系型数据库,是指采用了关系模型来组织数据的数据库
- 关系型数据库的最大特点就是事务的一致性
- 简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。
优点:
- 容易理解:二维表结构是非常贴近逻辑世界一个概念,关系模型相对网状、层次等其他模型来说更容易理解
- 使用方便:通用的SQL语言使得操作关系型数据库非常方便
- 易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率
- 支持SQL,可用于复杂的查询
- 缺点:
- 为了维护一致性所付出的巨大代价就是其读写性能比较差
- 固定的表结构
- 高并发读写需求
- 海量数据的高效率读写
- 非关系型数据库(MongoDB、Redis、HBase)
- 特性:
- 使用键值对存储数据
- 分布式
- 一般不支持ACID特性
- 非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合
- 优点:
- 无需经过sql层的解析,读写性能很高
- 基于键值对,数据没有耦合性,容易扩展;
- 存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,而关系型数据库则只支持基础类型。
- 缺点:
- 不提供sql支持,学习和使用成本较高
- 无事务处理,附加功能bi和报表等支持也不好
- 特性:
数据库的四大冲突问题
- 脏读:某个事务读取的数据是另一个事务正在处理、还未提交的数据,另一个事务可能会回滚,造成第一个事务读取的数据是错误的
- 不可重复读:在一个事务里两次读入数据,但另一个事务已经更改了第一个事务涉及到的数据,造成两次读取同一个数据时,数据不一致
- 幻读:幻读是指当事务不是独立执行时发生的一种现象。例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
- 更新丢失:多个事务同时读取某一数据,一个事务成功处理好了数据,被另一个事务写回原值,造成第一个事务更新丢失
乐观锁和悲观锁
- 乐观锁:默认读数据的时候不会修改,所以不会上锁
- 悲观锁:默认读数据的时候会修改,所以会上锁
- 使用场景:乐观锁适用于多读写比较少的情况,省去锁的开销,加大系统的吞吐量
数据库索引有哪些类型?
- 普通索引:没有任何限制
- 唯一索引:索引列的值必须唯一,但允许有空值
- 主键索引:特殊的唯一索引,不允许有空值;一个表只能有一个主键
- 组合索引:多个字段组合作为索引