原格式笔记
其中select和from是必须的,其他关键词是可选的,这六个关键词的执行顺序 与sql语句的书写顺序并不是一样的,而是按照下面的顺序来执行
from:需要从哪个数据表检索数据
where:过滤表中数据的条件
group by:如何将上面过滤出的数据分组
having:对上面已经分组的数据进行过滤的条件
select:查看结果集中的哪个列,或列的计算结果
order by :按照什么样的顺序来查看返回的数据
为什么数据库要无损分解?
模式分解要满足:
无损连接是指分解后的关系通过自然连接可以恢复成原来的关系,即通过自然连接得到的关系与原来的关系相比,既不多出信息、又不丢失信息。
保持函数依赖分解是指在模式的分解过程中,函数依赖不能丢失的特性,即模式分解不能破坏原来的语义
数据库管理系统(DataBase Management System,DBMS):
(整理)用户与操作系统之间的一层数据管理软件, 是数据库的应用程序与数据库的接口,对数据进行组织、存储和管理
Data management software, is the interface between the application and the database
用户与操作系统之间的一层数据管理软件,计算机的基础软件。
在数据库建立、运用和维护时对数据库进行统一控制,以保证数据的完整性和安全性,并在多用户同时使用数据库时进行并发控制,在发生故障后对数据库进行恢复
数据库(DataBase,DB)是长期存储在计算机内、有组织的、可共享的大量数据的集合。
A collection of large amounts of data that are stored in a computer over a long period of time, organized and shareable.
数据库中的数据按一定的数据模型组织、描述和储存
具有较小的冗余度、较高的数据独立性和易扩展性,并可为各种用户共享。
三个基本特点:
永久存储
有组织
可共享
数据库系统(DBS)是由数据库、数据库管理系统、应用程序和数据库管理员(DBA)组成的存储、管理、处理和维护数据的系统
Composed of databases, DBMS, applications and DBA
特点:
数据结构化(Data structuring):数据库系统与文件系统的本质区别。
“整体”结构化:数据库中的数据不再仅仅针对某一个应用,而是面向整个组织或企业;不仅数据内部是结构化的,整体是结构化的,数据之间是有联系的
数据的共享性高、冗余度低且易扩充:避免数据之间的不相容性与不一致性
***数据独立性高(High data independence):
物理独立性:用户不关心数据在数据库中怎样存储
逻辑独立性:数据的逻辑结构改变,用户程序可以不变
数据由DBMS统一管理和控制(Centrally managed and controlled by DBMS)
安全性:保护数据以防止不合法使用造成的数据泄露和破坏
完整性:数据的正确性、有效性和相容性
并发控制
数据库恢复
范式概念
不好的关系模式存在的问题:P179
数据冗余
增删改异常
更新异常
插入异常
删除异常
1NF:一个关系模式R的所有属性都是不可分的基本数据项
插入异常:未选课学生不能插入
删除异常:放弃修一门课,只选修这一门课的学生被删除
错误例子:四川省成都市
正确:四川省,成都市
如关系模式S-L-C(Sno, Sdept, Sloc, Cno, Grade)
第二范式P182
R满足第一范式,且每一个非主属性完全函数依赖于任何一个候选码,则R满足第二范式
第二范式就是每一行被码唯一标识
不满足2NF:
学生信息表:学号,姓名,系名,系主任,课程名称,分数。
(正确:学号--》姓名,学号--系名,学号--》系主任,)
问题:部分依赖 分数 --依赖--》 (课程名称+学号)
正确,拆分表:
学生表:学号,姓名,系名,系主任;
学生成绩:学号,课程名称,成绩;
不满足第二范式的问题:
插入异常:
删除异常
修改复杂
S-L-C(Sno,Sdept,Sloc,Cno,Grade)
应该改为SC(Sno,Cno,Grade)和S-L(Sno,Sdept,Sloc)
3NF P184
R符合第三范式,则每一个非主属性既不传递依赖于码,也不部分依赖于码
3NF要求一个数据库表中不能包含其他表中已包含的非码信息
不满足3NF:
学生信息表:学号(主键),姓名,系名,系主任。
问题: 学号 --》 系名,系名--》系主任;存在传递依赖
拆分表:
学生信息表:学号(主键),姓名,系名;
学校系: 系名,系主任;
仍然不能完全消除关系模式中的各种异常情况和数据冗余
***BCNF(Boyce Codd Normal Form)修正的第三范式,扩充的第三范式 P184
每一个决定因素都包含码,消除任何属性对码的部分和传递函数依赖
不符合的例子:STJ,S学生,T教师,J表示课程
符合BCNF的关系模式:
所有非主属性对每一个码都是完整函数依赖
所有主属性对每一个不包含它的码也是完全函数依赖
没有任何属性完全函数依赖于非码的任何一组属性
1NF->2NF 消除非主属性对码的部分函数依赖
2NF->3NF 消除非主属性对码的传递函数依赖
3NF->BCNF 消除主属性对码的部分和传递函数依赖
规范化的价值:合理规范化的模型可应对需求变更,规范化数据重复降至最少(降低冗余)
1NF:确保原子性,原子性的粒度、原子性的价值,毎一列只冇单值,单个字段当做单个值来使用,不做拆分来验证和使用(同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性)
2NF:检查对键的完全依赖,价值在在于控制教据冗余和查询性能(满足第一范式且要求数据库表中的每个实例或行必须可以被组成主键的所有列唯一地区分)(检查对键的完全依赖)
3NF:检查属性的独立性(满足第二范式且要求一个数据库表的非主关键宇信息只能被主关键字区分,没有函数依赖)(检查属性的独立性)
***启发式规则
1.选择运算应尽可能先做。最重要、最基本的一条。常常可以使执行代价节约几个数量级,使计算的中间结果大大变小
2.把投影运算和选择运算同时进行。如有若干投影和选择运算,并且它们都对同一个关系操作,则可以在扫描此关系的同时完成所有这些运算以避免重复扫描关系
3.把某些选择同在它前面要执行的笛卡儿积结合起来成为一个连接运算。连接运算要比同样关系上的笛卡尔积省很多时间
4.把投影同其前或后的双目运算结合起来。没有必要为了去掉某些字段而扫描一遍关系
5.找出公共子表达式
事务是用户定义的一个数据库操作序列,这些操作要么全做,要么全不做,是一个不可分割的工作单位
事务的四个特性:ACID特性
原子性(Atomicity):事务的操作要么都做,要么都不做
一致性(Consistency)
事务的执行结果必须是使数据库从一个一致性状态变到另一个一致性状态
隔离性(Isolation)
一个事务的执行不能被其他事物干扰。即一个事务的内部操作及其使用的数据对其他并发事务是隔离的,并发执行的各个事务之间不能互相干扰
持续性(Durability)
持续性也称永久性。一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其执行结果有任何影响
并发操作带来的数据不一致:
1.丢失修改:一个事务的修改结果破坏了另一个事务的修改结果
2.不可重复读:在两次‘ 读’ 操作之间插入了另一个事务的‘ 写’
3.读“脏”数据:一个事务读取了另一个事务未提交的修改结果
基本的封锁类型
排他锁(X锁)。写锁(exclusive locks)
事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁为止
共享锁(S锁)。读锁 (share locks)
事务T对数据对象A加上S锁,则事务T可以读A但是不能修改A,其他事物只能再对A加S锁,而不能加X锁,直到T释放A上的S锁为止
11.7封锁的粒度 P320
多粒度封锁协议允许多粒度树中的每个结点被单独地加锁。对一个结点加锁意味着对这个结点的所有后裔结点也被加以同样类型的锁。在多粒度封锁中一个数据对象可能以两种方式封锁,显式封锁和隐式封锁
显式封锁是应事务的要求直接加到数据对象上的锁
隐式封锁是该数据对象没有被独立加锁,是由于其上级结点加锁而使该数据对象加上了锁
意向锁——DBMS无须逐个检查下一级结点的显式封锁
含义:如果对一个结点加意向锁,则说明该结点的下层结点正在被加锁;对任意结点加锁时,必须先对它的上层结点加意向锁
三种常用的意向锁
1.IS锁(意向共享锁):后裔结点拟(意向)加S锁
2.IX锁(意向排他锁):后裔结点拟(意向)加X锁
3.SIX锁(共享意向排他锁):对它加S锁,再加IX锁。对某个表加SIX锁,表示该事务要读整个表(S),同时会更新个别元组
作用:
提高了系统的并发度
减少了加锁和解锁的开销
在实际的数据库管理系统产品中得到广泛应用
S与S,IS相容
X与一切不容
IS除了X都相容
IX与IS,IX相容
SIX与IS相容
B/ B+ 树是一种多级索引组织方法,是适合于组织存放在外存的大型磁盘文件的一种树状索引结构。其中用得比较多的是B+树
B/ B+ 树的结点划分
叶结点: B/ B+ 树的最下一级索引是树的叶结点
内部结点: B/ B+ 树中的其它结点( ( 非叶结点) ) ,其中:
根结点: B/ B+ 树的最上一级索引是树的根结点
B+ 树的特点
平衡性:从树的根结点到每个叶子结点的路径都是等长的。
过半性:每个结点(除根结点外)所对应的磁盘块至少被占用一半的存储空间。
顺序性:既提供从根结点开始的随机查找关键字功能,也能根据索引关键字的值的排序进行顺序访问。
自适应性:自动保持与数据文件大小相适应的索引层次。
B+树与B树的比较
组织方式不一样
B+树:所有有效的索引关键字值都必须存储在叶结点中,其内部结点中的键值只用于索引项的查找定位
B树:有效的索引关键字值可以出现在B树的任意一个点中。
内部结点不同
B+树:关键字值+子树指针
B树:关键字值+记录指针+子树指针
因此B树结点的扇出(即一个结点可以拥有的最大子结点数目)较小,从而导致整个B树的高度大于B+树的高度
随机查找效率的区别
B+树:所有关键字的查找速度基本一致
B树:依赖于查找关键字所在结点的层次
在B树中没有提供对索引关键字的顺序扫描功能。B树的插入、删除操作较B+树复杂
B* 树
规则
B*树是B+树的变种,相对于B+树他们的不同之处如下:
(1)首先是关键字个数限制问题,B+树初始化的关键字初始化个数是cei(m/2),b树的初始化个数为(cei(2/3m))
(2)分裂规则不同。B+树节点满时就会分裂,而B*树节点满时会检查兄弟节点是否满(因为每个节点都有指向兄弟的指针),如果兄弟节点未满则向兄弟节点转移关键字,如果兄弟节点已满,则从当前节点和兄弟节点各拿出1/3的数据创建一个新的节点出来;
特点
在B+树的基础上因其初始化的容量变大,使得节点空间使用率更高,而又存有兄弟节点的指针,可以向兄弟节点转移关键字的特性使得B*树额分解次数变得更少;
B/B+树: 用在磁盘文件组织,数据索引和数据库索引。
Trie树(字典树): 用在统计和排序大量字符串,如自动机。
红黑树: 平衡二叉树,广泛用在C++的STL中。如map和set都是用红黑树实现的。
B树索引的结构:由根指向子节点,B树将索引按顺序存储,在叶节点保存索引到字段及其对应数据在表中的位置指针。从根节点开始搜索,通过节点中的指针进入下一级节点,通过比较要查找的索引值和节点中的指针大小选择进入哪个子节点,最终要么找到对应叶节点,要么没找到。叶节点中有指向表中数据的指针。
何时使用:
a、仅需要索引访问表中很少一部分行时,索引提供以原子粒度访问数据的功能,可以快速定位所查找数据的位置;
b、虽然查询行数比较多,当索引包含多个字段,而要访问的字段全部包含在索引中时,查找只需通过索引而不用访问全表时。
Nosql的全称是Not Only Sql
1.存储方式:关系型数据库是表格式。而Nosql数据库则与其相反,通常存储在数据集中
2.存储结构:关系型数据库对应的是结构化数据,但是修改这些数据比较困难。而Nosql数据库基于动态结构,可以很容易适应数据类型和结构的变化。
3.存储规范:关系型数据库的数据存储为了更高的规范性,把数据分割为最小的关系表以避免重复,获得精简的空间利用。虽然管理起来很清晰,但是单个操作设计到多张表的时候,数据管理就显得有点麻烦。而Nosql数据存储在平面数据集中,数据经常可能会重复。单个数据库很少被分隔开,而是存储成了一个整体,这样整块数据更加便于读写
4.存储扩展:关系型数据库是纵向扩展,也就是说想要提高处理能力,要使用速度更快的计算机。而Nosql数据库是横向扩展的,它的存储天然就是分布式的,可以通过给资源池添加更多的普通数据库服务器来分担负载。
横向扩展是已扩展服务器的数量进行高并发的处理(增强处理业务的能力)
根据配置nginx的反向代理,转发服务器(配置的ip)进行轮换处理业务(可加入负载均衡器进行分发请求)
纵向扩展,是增加单机的处理能力,一般增加cpu的处理能力
5.查询方式:关系型数据库通过结构化查询语言来操作数据库(就是我们通常说的SQL)。SQL支持数据库CURD操作的功能非常强大,是业界的标准用法。而Nosql查询以块为单元操作数据,使用的是非结构化查询语言(UnQl),它是没有标准的。
6.事务
关系型数据库遵循ACID规则,而Nosql数据库遵循BASE原则(基本可用(Basically Availble)、软/柔性事务(Soft-state )、最终一致性(Eventual Consistency))。由于关系型数据库的数据强一致性,所以对事务的支持很好。关系型数据库支持对事务原子性细粒度控制,并且易于回滚事务。而Nosql数据库是在CAP(一致性、可用性、分区容忍度)中任选两项,因为基于节点的分布式系统中,很难全部满足,所以对事务的支持不是很好,虽然也可以使用事务,但是并不是Nosql的闪光点。
7.性能
关系型数据库为了维护数据的一致性付出了巨大的代价,读写性能比较差。在面对高并发读写性能非常差,面对海量数据的时候效率非常低。而Nosql存储的格式都是key-value类型的,并且存储在内存中,非常容易存储,而且对于数据的一致性是弱要求。Nosql无需sql的解析,提高了读写性能。
8.授权方式
关系型数据库通常有SQL Server,Mysql,Oracle。主流的Nosql数据库有redis,memcache,MongoDb。大多数的关系型数据库都是付费的并且价格昂贵,成本较大,而Nosql数据库通常都是开源的。
记忆起点:ACID(事务)->结构
结构->性能
关系型数据库
优点:
1.事务处理—保持数据的一致性
2.由于以标准化为前提,数据更新的开销很小(相同的字段基本上只有一处);
3.可以进行Join等复杂查询。
4.基于严格的数学
5.标准化SQL
6.事务
缺点
1.性能
2.纵向扩展
3.贵
nosql
优点
1. 简单的扩展(集群)
2. 高性能(它们可以处理超大量的数据):主要例子有Redis,由于其逻辑简单,而且纯内存操作,使得其性能非常出色,单节点每秒可以处理超过10万次读写操作;
3. 低廉的成本:这是大多数分布式数据库共有的特点,因为主要都是开源软件,没有昂贵的License成本;
4.灵活的数据模型。不需要事先对存储数据建立字段。
5.高可用。
缺点:
1.不提供对SQL的支持:如果不支持SQL这样的工业标准,将会对用户产生一定的学习和应用迁移成本;
2.不支持事务
3.现有产品的不够成熟:大多数产品都还处于初创期,和关系型数据库几十年的完善不可同日而语;
4.很难保证数据一致性
5.不能支持比较复杂的计算
6.NoSQL 并不完全安全稳定,由于它基于内存,一旦停电或者机器故障数据就很容易丢失数据,其持久化能力也是有限的,而基于磁盘的数据库则不会出现这样的问题
在数据库设计中,树通常三种模型
Adjacency model-邻接模型
Materialized path model-物化路径模型
Nested set model-嵌套集合模型
SQL执行步骤
语法检查:检查 SQL 拼写是否符合语法规范
语义检查:检查访问对象是否符合存在及用户是否具有相应权限
解析:在共享池中检查是否有完全相同的之前完全解析好的,如果存在,跳过选择执行计划和产生计划,直接运行
硬解析:就是对提交的 SQL 完全重新从头进行解析,创建解析树,生成执行计划对 SQL 的执行来说是开销昂贵的动作,在很多项目中对功能相同的代码要保持一致性,用绑定变量
软解析:在共享池(shared pool)中找到了与之完全相同的 SQL 解析好的结果会跳过硬解析后面的两个步骤
执行计划:以缩排列表的方式显示 SQL 语句的执行步骤
硬件优化:
1.存取路径:B+树索引存取方法、hash索引存取方法、聚簇存取方法
2.数据的物理布局:如何存储
3.可用内存
4.可用处理器
5.集中式存储与分布式存储。集中式存储是指将所有数据都存储在同一个节点上。这样有助于提高数据库查询和修改的效率。但是集中式存储有很大的风险,若节点出现不可逆破坏,将导致数据库崩溃。比如地震导致数据库损坏。
6.高效合理的操作算法:全表扫描、索引扫描、嵌套循环连接、排序-合并连接
7.固态存储
8.RAID
索引
索引的 5 种优点
通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
在使用分组和排序子句进行数据检索时,同样可以显着减少查询中分组和排序的时间。
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
应该建立索引的条件
1) 在经常需要搜索的列上,可以加快搜索的速度;
2) 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
3) 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
4) 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;外键建索引由于连接加快还会减少死锁几率。
5) 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
6) 在在经常使用在 WHERE 子句中的列上面创建索引,加快条件的判断速度。
系统(设计)
1.代数优化-优化器的启发式规则
2.计数器表
3.汇总表
4.分表
5.范式与反范式。设计合理的逻辑模式
6.外键加索引
7.尽可能避免使用自定义函数。再写 SQL语句时应尽可能避免使用自定义函数,因为对于自定义函数,优化器无法做出优化,若过度滥用自定义函数将导致数据库性能下降。但是在某些必要情况下,只能使用自定义函数来实现特定查询。
查询优化器的启发式规则
1.选择运算应尽可能先做。最重要、最基本的一条。常常可以使执行代价节约几个数量级,使计算的中间结果大大变小
2.把投影运算和选择运算同时进行。如有若干投影和选择运算,并且它们都对同一个关系操作,则可以在扫描此关系的同时完成所有这些运算以避免重复扫描关系
3.把投影同其前或后的双目运算结合起来。没有必要为了去掉某些字段而扫描一遍关系
4.把某些选择同在它前面要执行的笛卡儿积结合起来成为一个连接运算。连接运算要比同样关系上的笛卡尔积省很多时间
5.找出公共子表达式
1)范式和反范式
第一范式:每一列都是一个不可分割的原子数据项。
第二范式:第一范式基础上消除部分依赖。
第三范式:第二范式基础上消除传递依赖。
反范式是针对第三范式来说的,通过添加冗余的方式破坏了第三范式,前两个范式还是要遵循的。
范式的优点:
a.写入快,因为不需要写冗余数据,所以减少了写的负担。
b.更新快,因为通常只需要更新更少的数据。
c.由于没有冗余,所以不会造成数据不一致。
d.更少的需要GROUP BY和DISTINCT。
缺点是:需要关联。
范式的缺点,就是反范式的优点,不需要关联,并且因为在同一个表中,可以设计合适的索引。
实际应用中通常不会采用完成的范式,而是放置一些冗余,以减少表与表的关联,加快查询速度。
2)分表
如果表中的数据有状态,比如完成态和运行态,那么可以考虑将表分为运行态和完成态数据,数据转换到完成态时可以将数据归档到完成态表中,由于数据总是要运转到完成态,所以这样无论系统运行多长时间,运行态表中的数据几乎都是恒定的,而且完成态的数据除了统计分析用外,几乎不不需要查询,这样就大大提高了系统运行的速度,表中的数据量得到了控制。
另外对于统计分析的场景,为了减少表的union 可以要求业务查询从运行态和完成态两种状态中二选一。
对于一些海量数据,也可以考虑根据某个字段的值做hash,来分表存储,当然这加大了应用的复杂度,这没办法,通常没有十全十美的办法,架构就是根据实际应用场景做权衡,正所谓忠孝不能两全,只是某种办法更合适而已。
另外可以通过分布式数据库解决分表的问题,由分布式数据库自动分表存储,查询时自动合并,由分布式数据库中间件类屏蔽复杂性,各种脏活、累活交给它就是了。
3)汇总表
对于一些大数据量的报表统计工作,如果不是要求实时的话,可以定期汇总,比如每小时汇总一次或者每天汇总一次,如果要求实时的话,由于各种大表,各种group by,不但统计非常慢,而且容易影响正常的业务操作。笔者之前待的公司,每天晚上都开各种各样的定时任务进行数据汇总,在数据库不太忙的晚上,从12点干到早上6点,定时任务排的满满的,真是累死它的节奏啊,还好计算机不会闹脾气,发飙。。当然这样报表统计的数据是截止到昨天的,每次都晚一天,通常这是允许的。
4)计数器表
web应用为了记录点击次数,可以设计一个点击次数表,
create table hit_counter(cnt int unsigned not null);
由于只有一条记录这样锁争用太严重,想到了什么解决方案,同concurrenthashmap一样做锁拆分。
表结构修改为:
create table hit_counter(slot tinyint unsigned not null primary key,cnt int unsigned not null);
预先放入100条数据,这样修改的时候可以使用如下语句,
update hit_counter set cnt = cnt+1 where slot = RAND()*100;
获取的时候求和就可以了,select sum(cnt) cnt from hit_counter;
系统(应用上)
1.使用合理高效的SQL语句及方法,暗示SQL优化器进行优化
好的查询条件
关注结果集和中间数据集的大小
2.关注用户数,并发量。并据此检查自己的物理设计,系统设计
3.优化服务器配置
使用 SQL 语句要考虑的因素
1) 数据总量
Sql 考虑最重要的因素:必须访问的数据总量;没有确定目标容量之前,很难判断查询执行的效率
2) 定义结果集的查询条件
好的查询条件:满足此条件的数据很少,可以过滤很多数据
Where 字句:特别在子查询或视图中可能有多个 where 字句
过滤的效率有高有低,受到其他因素的影响
影响因素:过滤条件,主要的 sql 语句,庞大的数据对查询影响
3) 结果集的大小
查询所返回的数据量,重要而被忽略
取决于表的大小和过滤条件的细节
例外是若干个独立使用效率不高的条件结合起来效率非常高
从技术角度来看,查询结果集的大小并不重要,重要的是用户的感觉
熟练的开发者应该努力使响应时间与返回的记录数成比例
4) 获得结果集所涉及的表的数量:表的数量会影响性能
连接:太多的表连接(八张)就该质疑设计的正确性了;对于优化器,随着表数量增加,复杂度指数增长;编写太多表的复杂查询时,多种方式连接的选择失误几率很高
视图:会掩盖多表连接的事实
减少复杂查询和复杂视图
5) 并发的用户数(同时修改数据的用户数)
设计时要注意:数据块访问争用,阻塞,闩定,保证读取的一致性
一般而言,整体的吞吐量>个体响应时间
数据存贮采用固定大小的区块,可以存取多条记录,I/O 交互简单,在内存与缓冲中好处理;但是当修改后的数据太长,则会进行迁移到另一个 block 存储;数据块的太大,会带来数据块的访问争用的问题,影响并发性能
7.2 三种树状结构模型*
7.2.1 邻接模型
1. 邻接模型:id,parent_id(指向上级)
自顶向下查询,假设兄弟节点无序,主要用于单父节点。Connect by 相当容易实现
2. 特性:
a) 插入、移动、删除节点快捷
b) 只支持单父节点,不支持多父节点
c) Connect by 容易实现
d) 递归实现,用 oracle 的 with,表示出树的层次
e) 删除子树较难
f) 三种模型中性能最高,每秒返回的查询记录数最多,遍历一次,不是基于关系的处理,性能最好
7.2.2 物化路径
1. 物化模型:PathID(1,1.1,1.2,1.1.1,1.2.1,…),使用层次式的路径明确地标识出来,一般用字符串存路径。每一个节点都存储在树中的位置信息,它允许节点之间有顺序(因为路径的标识有顺序),比如家族族谱
2. 特性:
a) 查询编写不困难,找出适当的记录并缩排显示算容易
b) 计算由路径导出的层次不方便。
c) 查询复杂度主要在路径字符串的处理
d) 树的的深度要自己写函数计算,可以计算“.”的数目或者去掉“.”后字符串的长度
e) 子节点有顺序,但不应该暗示任何兄弟节点的排序
f) 会产生重复记录的问题
g) 物化路径 path 不应该是 KEY,即使他们有唯一性
h) 所选择的编码方式不需要完全中立
i) 三种模型中性能中等
7.2.3 嵌套集合模型
1. 嵌套集合模型:每一个节点都有一个左编号,都有一个右编号,left_num,right_num,某节点后代的 left_num 和 right_num 都会在该节点的 left_num 和 right_num 范围内
2. 特性
a) 易理解,查找某一个节点的子节点很容易,但是对结果集排序不好操作,缩排无法处理
b) 适合深度优先遍历
c) 动态计算深度困难,不要显示人造根节点,为了缩排显示要硬编码最大深度,缩排处理会降低查询性能
d) 数据元素之间不再是点和线的关系,而是以容纳和被容纳的方式
e) 计算量大,对存储程序要求高。它是基于指针的解决方案。
f) 数据更新,删除,插入开销很大,较少使用
g) 三种模型中,查询的性能最低
2.3 索引的局限性(索引的限制)
1. 为什么不为每一列建立索引
1) 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
2) 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
3) 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
2. 索引会带来的问题
1) 索引有可能降低查询性能,带来磁盘空间的开销和处理开销等
2) 太多的索引,让设计不稳定
3) 对于大量数据检索,索引效率反而更低
4) 创建索引会带来系统的维护和空间的开销
5) 数据修改需求大于检索需求时,索引会降低性能
3. 这些列不应该建立索引
1) 对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
2) 对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中, 结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
3) 对于那些定义为 text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少,不利于使用索引。
4) 当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。
2. 索引的 5 种优点
通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
在使用分组和排序子句进行数据检索时,同样可以显着减少查询中分组和排序的时间。
通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
3. 应该建立索引的条件
1) 在经常需要搜索的列上,可以加快搜索的速度;
2) 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
3) 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
4) 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;外键建索引由于连接加快还会减少死锁几率。
5) 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
6) 在在经常使用在 WHERE 子句中的列上面创建索引,加快条件的判断速度。
1. EAV表(entity-Attribute-Value)
2. 单表继承
3. 实体表继承
4. 类表继承
5. 半结构化设计
1. EAV表(entity-Attribute-Value)
createtable note_dictionary
(
dictionary_idnumber,
dictionary_type varchar2(50),--记录本的类型,就是那20多种记录本
dictionary_name varchar2(200)--记录本中的名称
);
--存储记录本的内容
createtable note_content
(
content_idnumber,
note_id number,--具体的一个记录本的id
dictionary_idnumber,--记录本中字段的id
contentvarchar2(1000)--字段的内容
);
优势
1. 灵活,增删字段不需要修改库表结构。不管entity是否存在继承关系,都可以使用EAV方式存储。
2. 库表设计简单(id、attr_name、value)
缺点:
1. 属性值的类型无法约束。如果是Date和number,只能用varchar2表示。统计也可能出现问题
2.不能加not null的约束和默认值。
3.后期维护数据较麻烦。
4.如果记录本之间是有关系,要建立关联关系,需要再加表,实现很复杂。
5.在一段时间后内容表会变得非常之笨重,系统中就属它数据量大。
6.牵一发而动全身。一处修改,无法确定其他地方是否会受影响。Java代码中使用了反射,debug很难调试,问题难定位
7.复杂查询都会变得复杂。
8.牺牲关系数据库本身的好处
9.无法使用完整性检查特性(外键)
2. 单表继承
将entity继承体系的所有属性都存储到一个表中,
实体属性如下:
库表设计如下:
user表:
优势
库表设计简单
不需要链表查询即可获取到子类的完整信息
规避了EAV设计的很多缺陷
劣势
添加子类的属性时需要修改user表(锁表,数据量大时影响很大)
对于子类,表中出现无关的属性,比如教师的行出现了student_number, 学生的行出现了subject
使用场景:
继承体系中子类属性较少的情况。比如可预见的时间内子类的属性都比较少时可以使用这种方式,毕竟查询简单,不需要联表查询。
3. 实体表继承
实体的属性是完整的,实体表继承,就是说每个实体都对应一个完整的表。
这种设计的优缺点:
优势
1. 获取完整对象不需要联表查询
2. 表中没有无关属性(跟单表继承的对比)
劣势
1. 在基类添加属性时需要修改多个表(比如在User类添加birthday属性,则需要在teacher/student表都添加column)
2. 表的结构松散,看不出类的继承关系
4.类表继承
那么在库表设计时也有三张表:user表、teacher表、student表(teacher表和student表有外键),如下:
优势
库表的层次结构清晰,库表直接反应了继承关系
为子类添加属性时不需要修改基类表(user表),为基类添加属性时不需要同时为多个表添加column
查询teacher、student的基类信息时不需要查询多个表(对比实体表继承方案)
劣势
获取对象完整数据需要联表查询(在表数据量大时联表查询性能差)
5. 半结构化设计
other_properties字段,对于teacher对象来说存{subject=english}, 对于student对象存:{student_number=123}
那么在查询时将整条记录查询到内存后再转为完整对象。
优势
可扩展性强,添加子类属性时不需要添加column,添加基类属性时才会添加column
查询简单,每行对应一个对象的完整信息,不需要联表查询
劣势
非结构化部分依旧有EAV设计的问题
对象的属性名没有约束(mysql没法限定用户名就叫username,业务可能不小心存为userName)
属性值的类型无法约束(age没法限定是int类型,业务可能不小心存了个‘abc’进去)
获取单个对象数据繁琐(查询一个完整对象,需要获取多条记录,还不能直接映射为User对象)
无法使用完整性检查特性(没法使用外键)
对于非结构化部分无法使用DB的聚合函数(比如sum、count等)