1.数据库设计三范式
满足的范式越高,数据库的数据冗余越少。
(1)第一范式:数据库表不包含多值属性。(属性的值是不可分割的原子数据,而不是数组或者集合)
(2)第二范式:满足第一范式的基础上,要求非主属性必须完全依赖于主键,而不是依赖于 主键的一部分。
(3)第三范式:满足第二范式的基础上,要求非主属性不能依赖于其他非主属性。
2.数据库索引
(1)数据库索引是对数据库表中一个或多个列进行排序的结构。
(2)索引的分类:普通索引(没有任何限制),唯一索引(索引列的值唯一),主键索引(主键会默认创建索引,因此主键索引是特殊的唯一索引),组合索引(对两个或多于两个列建立的索引,最左前缀:加速查询只适用于搜索列是索引的最左部分)。
(3)聚簇索引(只有InnoDB和solidDB拥有):聚簇索引不是一种特定的索引类型,而是一种数据的存储方式。聚簇索引建立的B树,其叶节点保存了索引以及数据行,而非聚簇索引,叶节点只保存行号。
聚簇索引的数据的物理存放顺序与索引顺序是一致的,即:只要索引是相邻的,那么对应的数据一定也是相邻地存放在磁盘上的。
聚簇索引的优点:
A:可以把相关数据保存在一起,如:实现电子邮箱时,可以根据用户ID来聚集数据,这样只需要从磁盘读取少量的数据页就能获取某个用户全部邮件,如果没有使用聚集索引,则每封邮件都可能导致一次磁盘IO。
B:数据访问更快,聚集索引将索引和数据保存在同一个btree中,因此从聚集索引中获取数据通常比在非聚集索引中查找要快
C:使用覆盖索引扫描的查询可以直接使用页节点中的主键值
聚簇索引的缺点:
A:聚簇数据最大限度地提高了IO密集型应用的性能,但如果数据全部放在内存中,则访问的顺序就没有那么重要了,聚集索引也没有什么优势了
B:插入速度严重依赖于插入顺序,按照主键的顺序插入是加载数据到innodb表中速度最快的方式,但如果不是按照主键顺序加载数据,那么在加载完成后最好使用optimize table命令重新组织一下表
C:更新聚集索引列的代价很高,因为会强制innodb将每个被更新的行移动到新的位置
D:基于聚集索引的表在插入新行,或者主键被更新导致需要移动行的时候,可能面临页分裂的问题,当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分裂成两个页面来容纳该行,这就是一次页分裂操作,页分裂会导致表占用更多的磁盘空间
E:聚集索引可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候
F:二级索引可能比想象的更大,因为在二级索引的叶子节点包含了引用行的主键列。
G:二级索引访问需要两次索引查找,而不是一次
3.数据库事务
3.1 ACID
(1)Atomicity(原子性):一个事务中的操作以原子方式执行,不可分割。
(2)Consistency(一致性)事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
(3)Isolation(隔离性):一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
(4)Durability(持久性):事务结束后对数据的修改是永久的。
3.2 四种隔离级别
参考:www.open-open.com/lib/view/open1477901691009.html
SQL标准定义的四种隔离级别:
(1)Read Uncommitted:在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。
(2)Read Committed:这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
(3)Repeatable Read:这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
(4)Serializable:这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。
脏读:读取到未提交的数据。
不可重复读:在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间,有另外一个事务更新的原有的数据。
幻读:幻读问题是指一个事务的两次不同时间的相同查询返回了不同的的结果集。例如:一个 select 语句执行了两次,但是在第二次返回了第一次没有返回的行,那么这些行就是“phantom” row。
如何避免幻读:由于 SESSION_A 第一次的查询开始于 SESSION_B 插入数据前,所以创建了一个以SELECT操作的时间为基准点的 read view,避免了幻读的产生。所以在 SESSION_A 的事务结束前,无法看到 SESSION_B 对表 read_view 做出的任何更改 (insert,delete,update)
大致的区别在于不可重复读是由于另一个事务对数据的更改所造成的,而幻读是由于另一个事务插入或删除引起的。
3.3 乐观锁和悲观锁
(1)乐观锁:乐观锁假设数据一般情况下不会造成冲突,因此在提交更新的时候才对数据是否存在冲突进行检验。如果存在数据冲突则更新失败。具体的实现是位数据库表添加一个version字段,每次更新操作都会修改version。提交时使用CAS操作修改version,如果修改成功,则更新数据成功,否则操作失败。
(2)悲观锁:事务开始时即获取数据的排他锁,防止其他进程读取或修改该段数据。
在实际生产环境里边,如果并发量不大且不允许脏读,可以使用悲观锁;但如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法.。
4.数据库视图
在SQL中,view 是基于SQL语句的结果集的可视化的表。
CREATE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition;
参考:blog.csdn.net/buhuikanjian/article/details/53105416
优点:
(1)将经常使用的数据定义为视图,简化了以后的操作。
(2)安全性,用户只能查询和修改能看到的数据。
视图和表的区别:
(1)视图是已经编译好的sql语句,是基于sql结果集的可视化的表,并不占有实际的物理空间。
(2)表里的数据增加或者删除的时候,视图里的内容也随着变化
(3)视图的建立和删除只影响视图本身,不影响对应的基本表
(4)一般来说你可以用update,insert,delete等sql语句修改表中的数据,而对视图只能进行select操作。但是也存在可更新的视图,对于这类视图的update,insert和delete等操作最终会作用于与其相关的表中数据。因此,表是数据库中数据存储的基础,而视图只是为了满足某种查询要求而建立的一个对象。
5. B树和B+树
* https://www.jianshu.com/p/ea8d0418d4ed
* https://blog.codinglabs.org/articles/theory-of-mysql-index.html
6. SQL基础
1. 内连接:返回左表和右表的交集部分
2. 左外连接:返回全部的左表数据,右表符合搜索条件的部分展示,不存在的部分显示NULL
3. 右外连接:返回全部的右表数据,左表符合搜素条件的部分展示,不存在的部分显示NULL
4. group by使用
(1)select 类别, avg(数量) AS 平均值 from product group by 类别; //获取每种类别商品数量的平均值
(2)select 类别, sum(数量) as 数量之和 from product group by 类别 //获取每种类别商品数量之和
(3)where 子句的作用是在对查询结果进行分组前,即在分组之前过滤数据。where条件中不能包含聚合函数。
(4)having 子句的作用是筛选满足条件的组,即在分组之后过滤数据。条件中经常包含聚合函数。
(5)select 类别, sum(数量) as 数量之和 from product group by 类别 having sum(数量) > 18