赞
踩
今天给大家整理一些数据库必知必会的面试题,一起来看吧。
关系型数据库的优点
容易理解,因为它采用了关系模型来组织数据。
可以保持数据的一致性。
数据更新的开销比较小。
支持复杂查询(带 where 子句的查询)
非关系型数据库(NOSQL)的优点
无需经过 SQL 层的解析,读写效率高。
基于键值对,读写性能很高,易于扩展
可以支持多种类型数据的存储,如图片,文档等等。
扩展(可分为内存性数据库以及文档型数据库,比如 Redis,MongoDB,HBase 等,适合场景:数据量大高可用的日志系统/地理位置存储系统)。
Server 层按顺序执行 SQL 的步骤为:
客户端请求 -> 连接器(验证用户身份,给予权限)
查询缓存(存在缓存则直接返回,不存在则执行后续操作)
分析器(对 SQL 进行词法分析和语法分析操作)
优化器(主要对执行的 SQL 优化选择最优的执行方案方法)
执行器(执行时会先看用户是否有执行权限,有才去使用这个引擎提供的接口)-> 去引擎层获取数据返回(如果开启查询缓存则会缓存查询结果)
根本原因
索引的出现,就是为了提高数据查询的效率,就像书的目录一样。
对于数据库的表而言,索引其实就是它的“目录”。
扩展
创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
帮助引擎层避免排序和临时表
将随机 IO 变为顺序 IO,加速表和表之间的连接。
三种常见的索引底层数据结构:分别是哈希表、有序数组和搜索树。
哈希表这种适用于等值查询的场景,比如 memcached 以及其它一些 NoSQL 引擎,不适合范围查询。
有序数组索引只适用于静态存储引擎,等值和范围查询性能好,但更新数据成本高。
N 叉树由于读写上的性能优点以及适配磁盘访问模式以及广泛应用在数据库引擎中。
扩展(以 InnoDB 的一个整数字段索引为例,这个 N 差不多是 1200。棵树高是 4 的时候,就可以存 1200 的 3 次方个值,这已经 17 亿了。考虑到树根的数据块总是在内存中的,一个 10 亿行的表上一个整数字段的索引,查找一个值最多只需要访问 3 次磁盘。其实,树的第二层也有很大概率在内存中,那么访问磁盘的平均次数就更少了。)
根据叶子节点的内容,索引类型分为主键索引和非主键索引。
主键索引的叶子节点存的整行数据,在InnoDB里也被称为聚簇索引。
非主键索引叶子节点存的主键的值,在InnoDB里也被称为二级索引。
InnoDB 存储引擎:B+ 树索引的叶子节点保存数据本身,其数据文件本身就是索引文件。
MyISAM 存储引擎:B+ 树索引的叶子节点保存数据的物理地址,叶节点的 data 域存放的是数据记录的地址,索引文件和数据文件是分离的。
两个考虑因素:
InnoDB 需要执行的场景和功能需要在特定查询上拥有较强的性能。
CPU 将磁盘上的数据加载到内存中需要花费大量时间。
为什么选择 B+ 树:
哈希索引虽然能提供O(1)复杂度查询,但对范围查询和排序却无法很好的支持,最终会导致全表扫描。
B 树能够在非叶子节点存储数据,但会导致在查询连续数据可能带来更多的随机 IO。
而 B+ 树的所有叶节点可以通过指针来相互连接,减少顺序遍历带来的随机 IO。
普通索引还是唯一索引?
由于唯一索引用不上 change buffer 的优化机制,因此如果业务可以接受,从性能角度出发建议你优先考虑非唯一索引。
覆盖索引:
在某个查询里面,索引 k 已经“覆盖了”我们的查询需求,称为覆盖索引。
覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
索引下推:
MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
对索引使用左或者左右模糊匹配,也就是 like %xx 或者 like %xx% 这两种方式都会造成索引失效。原因在于查询的结果可能是多个,不知道从哪个索引值开始比较,于是就只能通过全表扫描的方式来查询。
对索引进行函数/对索引进行表达式计算,因为索引保持的是索引字段的原始值,而不是经过函数计算的值,自然就没办法走索引。
对索引进行隐式转换相当于使用了新函数。
WHERE 子句中的 OR语句,只要有条件列不是索引列,就会进行全表扫描。
直接创建完整索引,这样可能会比较占用空间。
创建前缀索引,节省空间,但会增加查询扫描次数,并且不能使用覆盖索引。
倒序存储,再创建前缀索引,用于绕过字符串本身前缀的区分度不够的问题。
创建 hash 字段索引,查询性能稳定,有额外的存储和计算消耗,跟第三种方式一样,都不支持范围扫描。
- 反过来,假设一个业务的更新模式是写入之后马上会做查询,那么即使满足了条件,将更新先记录在 change buffer,但之后由于马上要访问这个数据页,会立即触发 merge 过程。这样随机访问 IO 的次数不会减少,反而增加了 change buffer 的维护代价。
当需要更新一个数据页时,如果数据页在内存中就直接更新;而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InnoDB 会将这些更新操作缓存在 change buffer 中。
这样就不需要从磁盘中读入这个数据页了,在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行 change buffer 中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。
注意唯一索引的更新就不能使用 change buffer,实际上也只有普通索引可以使用。
适用场景:
- 对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时 change buffer 的使用效果最好。这种业务模型常见的就是账单类、日志类的系统。
MySQL 在真正开始执行语句之前,并不能精确地知道满足这个条件的记录有多少条。
而只能根据统计信息来估算记录数。这个统计信息就是索引的“区分度。
redo log 主要用于 MySQL 异常重启后的一种数据恢复手段,确保了数据的一致性。
其实是为了配合 MySQL 的 WAL 机制。因为 MySQL 进行更新操作,为了能够快速响应,所以采用了异步写回磁盘的技术,写入内存后就返回。但是这样,会存在 crash后 内存数据丢失的隐患,而 redo log 具备 crash safe 的能力。
第一点:redo log 可确保 innoDB 判断哪些数据已经刷盘,哪些数据还没有
redo log 和 binlog 有一个很大的区别就是,一个是循环写,一个是追加写。也就是说 redo log 只会记录未刷盘的日志,已经刷入磁盘的数据都会从 redo log 这个有限大小的日志文件里删除。binlog 是追加日志,保存的是全量的日志。
当数据库 crash 后,
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。