数据库学习
吊打面试官(数据库大厂)
另外吐血推荐机器学习入门
索引
索引的常见实现有三种 Hash索引,B树索引(B+),位图索引。这三种索引适用的情况也不相同
Hash索引只适合等值查询,不支持范围查询/模糊查询(不支持是说明对于该种查询,索引失效)
B树索引适合大多数查询,但不适合值的类型很少的列(即选择度低,例如性别)
位图索引对于OLTP不适合,因为对于值的更新,会对相同值的所有数据加锁,不适合大量的增删改。
在OLAP比较合适,同时对值类型少的列表现更好。
联机事务处理OLTP(on-line transaction processing)、联机分析处理OLAP(On-Line Analytical Processing)
索引实现原理
Hash 索引采用的Hash Table 进行实现,每次查询时,都根据值计算Hash 值进行检索。故适合等值查询,因为性能接近O(1),不过Hash 没法做范围查询。
B树索引采用的是B+树(Mysql)或B树(Oracle)
位图索引采用的是向量
B树和B+树区别,B+树把所有节点放在叶子节点底部,索引部分不包括指向数据的指针。B树把索引部分也是数据节点,包含指向数据的指针,叶子节点并不包含所有节点。
B+树的优点,底层包含所有数据节点且有序,方便遍历。索引部分不包含数据指针,单个索引更小,因此一个磁盘区块能存下更多索引。
数据库取数据的流程是:查询索引确定数据所在的磁盘块,取出数据的对应磁盘块。对于很大的表,索引并不能完全放在内存中,那查询索引时也要取磁盘块了,所以采用B树/B+树的原因就是其可以减少磁盘读取次数(高度低),并且相同数据其存储位置相近
3. Hash索引和B+树所有有什么区别或者说优劣呢?
首先要知道Hash索引和B+树索引的底层实现原理:
hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据.B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据.
那么可以看出他们有以下的不同:
- hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询.
因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询.而B+树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围.
- hash索引不支持使用索引进行排序,原理同上.
- hash索引不支持模糊查询以及多列索引的最左前缀匹配.原理也是因为hash函数的不可预测.AAAA和AAAAB的索引没有相关性.
- hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询.
- hash索引虽然在等值查询上较快,但是不稳定.性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差.而B+树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低.
哈希索引适合等值查询,但是无法进行范围查询
哈希索引没办法利用索引完成排序
哈希索引不支持多列联合索引的最左匹配规则
如果有大量重复键值的情况下,哈希索引的效率会很低,因为存在哈希碰撞问题
因此,在大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度.而不需要使用hash索引.
聚簇索引 和 非聚簇索引
聚簇索引记录的物理顺序与索引的顺序一致,非聚簇索引记录的物理顺序与逻辑顺序没有必然的联系。
Mysql 有两种引擎InnoDB 和MyIASM。首先一些基础知识是,任何建立的索引,在数据库中都是以索引文件存储。而数据本身也采用文件存储,形成数据文件。
InnoDB默认采用聚簇索引,而MyIASM采用非聚簇索引
对于非聚簇索引,索引的叶子节点仅仅记录数据节点的位置(磁盘位置),因此索引文件和数据文件分为两部分。对于非主键的索引,其索引叶节点也是指向数据节点的磁盘位置(和主键索引一样)。因此查询时,是首先查询索引获取数据的磁盘位置,然后再从数据文件中读取指定数据。
对于聚簇索引,索引的叶子节点包含数据节点(主键索引),因此只有一个文件,而对于非主键索引,其索引的叶节点是数据的主键。使用非主键索引时,首先根据非主键索引查到复合条件的数据的主键,然后查询主键索引,获取数据。
聚簇的数据有一些重要的优点:
- 可以把相关数据保存在一起。例如实现电子邮箱时,可以根据用户ID来聚集数据,这样只需要从磁盘读取少数的数据页就能获取某个用户的全部邮件。如果没有聚簇索引,则每封邮件都可能多一次磁盘IO。
- 数据访问更快。聚簇索引将索引和数据保存在同一个B+Tree中,因此从聚簇索引中获取数据通常比在非聚簇索引中查找要快。(不需要回表再次查询)
- 使用覆盖索引扫描的查询可以直接使用叶节点中的主键值。
- 天然适合顺序遍历
缺点:
- 聚簇数据最大限度地提高了IO密集型应用的性能,但如果数据全部放在内存中,则访问的顺序就没那么重要了,聚簇索引也就没什么优势了。
- 插入速度严重依赖于插入顺序(不稳定)。因为插入时要保存数据的有序,因此可能会移动原数据。按照主要的顺序插入是加载数据到InnoDB表中速度最快的方式。但如果不是按照主键顺序加载数据,那么在加载完成后最好使用optimize table命令重新组织一下表。
- 更新聚簇索引列的代价很高,因为会强制InnoDB将每个被更新的行移动到新的位置。
- 基于聚簇索引的表插入新行,或者主键被更新导致需要移动行的时候,可能面临”页分裂(page split)“的问题。当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分裂成两个页面来容纳该行,这就是一次分裂操作。页分裂会导致表占用更多的磁盘空间。
- 聚簇索引可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候。
- 二级索引(非聚簇索引)可能比想象的要更大,因为在二给索引的叶子节点包含了引用行的主键列。
- 二级索引访问需要两次索引查找,而不是一次。
事务
这种把多条语句作为一个整体进行执行的功能,被称为数据库事务。事务是一系列的操作,他们要符合ACID特性事务中的操作要么全部成功,要么全部失败
ACID 特性
A=Atomicity
原子性,就是上面说的,要么全部成功,要么全部失败.不可能只执行一部分操作.
C=Consistency
一致性,事务完成后,所有数据的状态都是一致的。即A账户只要减去了100,B账户则必定加上了100;
I=Isolation
隔离性: 通常来说:一个事务在完全提交之前,对其他事务是不可见的.意味着有例外情况.
D=Durability
持久性,一旦事务提交,那么就永远是这样子了,哪怕系统崩溃也不会影响到这个事务的结果.
同时有多个事务在进行会怎么样呢?
多事务的并发进行一般会造成以下几个问题:
-
脏读: 所谓脏读是指一个事务中访问到了另外一个事务未提交的数据
A事务读取到了B事务未提交的内容,而B事务后面进行了回滚.(读取的内容不对)
-
不可重复读: 一个事务读取同一条记录2次,得到的结果不一致:
当设置A事务只能读取B事务已经提交的部分,会造成在A事务内的两次查询,结果竟然不一样,因为在此期间B事务进行了提交操作.(两次读取的内容不一致)
-
幻读: 一个事务读取2次,得到的记录条数不一致
A事务读取了一个范围的内容,而同时B事务在此期间插入了一条数据.造成"幻觉".
四大隔离级别
- Read uncommitted(读未提交)
- Read committed(读提交)
- Repeatable read(可重复读)
- Serializable (序列化)
三大范式
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。(原子性)
第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。其他列必须与主键形成完全函数依赖 (相关性)
也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中
第三范式需要确保数据表中的每一列数据都和主键直接函数依赖(直接相关),而不能间接相关。(直接相关性)
说白了,就是其他列完全依赖且只依赖主键