之前读过了sql调优的前几章:整体架构、内存架构、存储架构,这节读sql调优的对象类型。依照数据库为Orcale数据库。
数据库对象包含表、索引、视图、存储过程等类型。我们对数据库的操作就是通过对其中各种对象的创建、存储和操作完成的。
表是数据库组织和管理数据的基本单位,是数据库提供给用户的一个访问数据的逻辑对象。
- 表分为关系表和对象表。对象表相对来说用的较少,对象表是Oracle增加了融入对象的概念,将表中每一行数据视为一个对象,对象可设置各种成员函数和存储过程等,对象表具体数据实质也是存储在关系表中。关系表包括堆表(Heap-organized Table)、索引组织表(Index-organized Table)、外部表(External Table)。
- 表中的数据,事实上是存储在段(Segment)中的。非分区表,一个表对应一个段,分区表一个分区对应一个段,有子分区的表一个子分区对应一个段,其它数据库类型(如索引、物化视图等)与表类似。用户或系统数据以及物化视图都用的堆表方式存储,对应段中的数据逻辑上无序。
- 表分区是将表里的数据由原来存储在一个段中变为存储在多个段中,方便数据管理和维护。正确分区可以提升数据查询和操作性能。但应用分区表时,需更多考虑分区剪裁(Partition Oruning,即优化器可以从from和where中提取出需查询的分区)的问题。当数据量足够大(Oracle给出的判断基准是单表数据超过2GB认为足够大),并且分区后能简化用户管理和维护数据、提高对数据查询和操作性能时才可适用分区。
索引是建立在表上的逻辑对象,也是提高检索效率最为常用的手段。
- 索引的数据最终也是存储在段中的,索引并不按照堆的逻辑结构组织和存储。它的存储方式与类型有关。如B树(B*Tree)索引、位图(Bitmap索引等)。
- 索引不是必须的,对表来说只是可选项。它会提高对表数据的检索效率,但会影响DML(Data Manipulation Language)操作(例如增删改)的性能。因为DML操作修改表数据时,还需自动修改相关索引。索引的列基数为一个列中不同值的个数,如记录用户信息的表中,用户性别列只有男、女、未知三个选项,则列基数为3,每个用户的手机号都不同,则手机号列基数为表中数据行的数量。列基数/总行数的百分比就叫作列选择性,列选择性会在优化器根据索引查询时适用,若列选择性很低,则优化器会认为全表扫描查询更为有效率,不根据索引去查询了。列直方图是反映列数据分布情况的列统计数据。索引聚集因子(Clustering factor)是指基于索引键值的表中数据行的顺序数,就是一个索引块中对应的数据是否基本在一个数据块或者相邻数据块中,反映了已索引的列是否基本有序,索引聚集因子越小,查询时扫描的数据块越少,查询效率就越高。
- 本地索引(Local Index)是创建在分区表上的分区索引,本地索引分区与分区表分区一一对应。全局索引(Global Index)也是创建在分区表上的分区索引,但全局索引可能不分区或者即使分区,对应的索引分区也与表的分区不一致。本地索引方便用户管理和维护,根据索引查询时效率也相对较高,但它在数据应用时需更多考虑分区键和分区剪裁的因素。全局索引无需考虑分区键和分区剪裁,但用户删除截断数据时易导致索引失效不可用。
- B*索引是比较常用的索引,B*树的图形可以直接搜索到,它每个分支存储索引键值,对应的叶子节点存储一个个的[键值,rowid]对,键值相同而rowid不同的值也都会存入叶子块中。而位图索引结构也与B*树结构相同,但是位图索引的叶子结点存储的是每个键值的位图,那么键值相同而rowid不同的值就只需存储一个位图。位图中集中记录了键值对应的rowid。基于上述特点,位图索引可以极大减少索引所占空间,因此能极大提高查询性能,但是因为同一个键值的数据均指向了同一个位图,所以写操作时修改位图索引需要对整个位图数据加范围锁,造成并发写操作时性能很差。且索引列的选择性或离散度较高时,位图索引占用空间也会变大。
簇是一种包含一个或多个表数据的数据库对象,这些被包含的表有一个或多个共同列。Oracle数据库把多个表中具有相同簇键值的行存储在一起。簇上的数据会在磁盘的同一个区域中,便于减少磁盘块扫描次数,快速查询。
- 簇分为索引簇和哈希簇。索引簇通过簇键列上的索引来查找数据的簇,哈希簇通过簇键列的哈希值来查找数据的簇。索引簇主要用于需要经常关联表查询的情况,比如student表和score表经常通过student表的stu_id进行关联查询时则可采用索引簇。而哈希簇适用于单个表的情况,它会根据散列算法计算出存储行的物理存储位置,从而直接获取数据。
视图是一种虚的、定义的逻辑对象,主要用于简化业务逻辑、方便开发维护及实现数据库的安全性等,它对于实际的数据存储开发并无性能上的提升。
- 视图不包含数据,只是被存储的查询。它可以屏蔽数据列或数据行,为数据提供了安全机制。
物化视图是一种实的、定义的逻辑对象。除了名字都有视图,物化视图和视图并没什么关系。物化视图实际存储数据,有对应存储数据的段。
- 物化视图实际存储查询出来的数据,对于存在多表关联、复杂sql的查询,物化视图可以存储这部分查询数据,达到优化性能的目的。它能被用来汇总、计算、复制、分发数据,适用于数据仓库、分布式环境等。
- 物化视图类似于表,可以分区,也可以建索引
- 物化视图既然会存储多表复杂查询的数据,那么就会涉及到存储数据与原来的多个基表数据同步的过程。物化视图的同步也即刷新分为手动和自动,刷新数据分为全部和增量,自动刷新分为定时和实时。
同义词是虚的、定义的逻辑对象,不存储任何数据,仅仅是其它对象的一个别名。
序列也是虚的、定义的逻辑对象,不存储任何数据,用户可以通过它获取一系列有序值。
- 序列值有最多38位数字的上限。
- 序列定义包含序列名、升降序、步长、内存中缓冲数字等,定义会储存在系统字典里。
- 负载很高时,序列可能会形成较大的瓶颈。
索引组织表(IOT,Index Organized Table)是实的对象,兼具索引和表的特性。它的存储结构是个B*Tree,数据在索引列上有序,但是叶子节点存储了键值和数据行,但没有ROWID,所以它实际存储了表数据。
过程和函数是虚的、定义的逻辑对象,不存储数据,功能是通过数据库编码和调用运行来解决问题或执行任务。
- 过程和函数本质是一种数据库对象,由一组SQL和其它PL结构语句组合在一起,存储在数据库中。作为一个运行单元,用来解决特定问题或执行一组任务。
- 过程和函数允许调用者只传入、传出参数,封装了业务逻辑。
- 除了函数有返回值之外,过程与函数是一致的。
- 对于场景多变、问题多变的情况,不适合采用过程和函数,且DBA通常也不认为后台开发可以写出很好的过程和函数,所以针对这些情况,业务逻辑最好还是放在后台工程去处理比较合适。
触发器(Trigger)是虚的、定义的逻辑对象,不存储数据,通过数据库编码和时间自动触发运行来解决问题或执行任务。
- 触发器本质也是一种由SQL语句和其他PL结构语句组合的数据库对象,也是作为一个单元来运行,解决特定问题或执行一组任务
- 触发器与过程及函数区别在于,触发器通过某个事件去自动触发,不需要也不可以人工传入或传出参数
包(Package)是虚的、定义的逻辑对象,不存储数据,功能是组织代码对象。包可以让用户更方便的管理、维护和应用包内的代码对象。
约束是虚的、定义的逻辑对象,不存储数据,通过一些内部或自定义逻辑实现对数据的检查和限制。分为主键约束、唯一性约束、非空约束、自定义约束、外键约束等。