SQL Server 查询优化 索引的结构与分类

SQL Server 索引结构及其使用 SQL+Server+索引结构及其使用 欢迎下载 立即下载

一、索引的结构

关系型数据库中以二维表来表达关系模型,表中的数据以页的形式存储在磁盘上,在SQL SERVER中,数据页是磁盘上8k的连续空间,那么,一个表的所有数据页在磁盘上是如何组织的呢?分两种情况:一是数据页间无序、随机地存储在磁盘上,这样的表叫做堆表;二是数据页间按某个表字段的值有序地存储在磁盘上,这样的表做索引组织表。

 

索引是什么?从物理结构上可分为两种:聚集索引和非聚集索引。将表中的数据有序地组织起来的索引称为聚集索引,一个表只有一个聚集索引,表上其他的索引都是非聚集索引。

 

1.1、聚集索引结构

(1)聚集索引将表内的数据进行有序的组织,并不是指磁盘上数据页内数据的物理顺序,也不是指数据页在磁盘上的物理顺序,而是数据页间逻辑上以树型结构链接起来;

create table t

(

ID       int,

NAME     varchar(100)

AGE      int,

)

GO

INSERT INTO t VALUES(1,'张一',20)

INSERT INTO t VALUES(2,'张二',25)

INSERT INTO t VALUES(4,'张三',21)

INSERT INTO t VALUES(5,'李二',23)

INSERT INTO t VALUES(7,'李三',24)

INSERT INTO t VALUES(8,'李四',22)

GO

create CLUSTERED index IX_t_ID on t(ID)

 (

2)聚集索引的非叶子节点(即索引节点)行中,只包含下一节点的第一个键值及指向下一节点的指针,指针的格式为:文件编号+页编号,长度为2Byte+4Byte=6Byte;

(3)聚集索引的叶子节点行就是表中的数据行;

(4)没有聚集索引的表,结构如下:

堆表中的数据页没有经过组织,随机的存放在磁盘上,通过IAM页进行管理,可以知道哪些数据页属于某个表以及数据页的分配情况,对于数据页的结构及数据库引擎对其管理,这里不多作介绍,详见《SQL Server 存储引擎》系列。

(5)数据库引擎根据系统目录判断当前表是否为索引组织表,以选择索引组织表的root_page或堆表的first_IAM_page及first_page,即可对表进行扫描;

(6)索引组织表和堆表包含的数据行是一样的,只是组织形式不同而已;

 

1.2、非聚集索引结构

(1)非聚集索引是对聚集索引的索引;

(2)非聚集索引的索引节点行和聚集索引一样,只包含下一节点的第一个键值及指向下一节点的指针,指针的格式为:文件编号+页编号,长度为2Byte+4Byte=6Byte;

(3)非聚集索引的叶子节点行存储的是索引列和书签。如果是索引组织表,书签为聚集索引键;如果是堆表,书签为ROWID,长度为8Byte,即数据页号(4Byte)+文件号(2Byte)+槽号(2Byte)的行定位串;

create NONCLUSTERED index IX_t_AGE on t(AGE)

GO

SELECT * FROM t WHERE AGE=20

此时想要根据年龄20来查找数据。

如果是索引组织表,先根据AGE上的非聚集索引找到ID,此时ID值为1,然后再将ID=1带入聚集索引进行等值查找,最终在聚集索引的叶子节点得到该行的所有数据;

如果是堆表,先根据AGE找的应该是ID=1这一行数据的8字节的ROWID,然后再根据这个ROWID去找到该行的所有数据,即(1,'张一',20);

(4)无论是聚集索引还是非聚集索引的叶子节点上都有一个指向上下页的指针。

 

二、索引分类

1、SQL SERVER中索引分类

(1)B+树索引

目前关系型数据库中一种常见的索引组织结构。B+树,它是一多叉平衡排序树,直到叶子节点才会命中数据,以下简称B树,可参见相关《数据结构》的书籍;

 

(2)、全文索引

目前关系型数据库一种基于标记的索引组织结构,它不是B树结构,而是基于要索引的文本中的各个标记来创建倒排、堆积且压缩的索引结构。

 

(3)、XML索引

随着XML文本的应用,在各个关系型数据库中也相继提供了对这种数据结构的支持。XML 实例作为二进制大型对象 (BLOB) 存储在 xml 类型列中。对于列中的每个 XML对象,索引将创建几个数据行。该索引中的行数大约等于 XML对象中的节点数。

 

1.2、B树索引的分类

1.2.1、物理结构分类

(1)聚集索引

根据索引列值,按B树结构对表内数据进行组织;

 

(2)非聚集索引

对聚集索引的索引;

 

1.2.2、列值唯一性分类

(1)唯一索引

表中索引列的值唯一。

SQL SERVER在唯一性上认为NULL是相等的(ORACLE中唯一键是可以插入多个NULL值的),即唯一键中只允许出现一个NULL值,但在比较运算中认为NULL是不相等的,这点要注意;

 

(2)非唯一索引

表中索引列的值不唯一;

 

1.2.3、列个数分类

(1)复合索引

包含多个列的索引;

 

(2)单列索引

只包含一个列的索引。

 

1.2.4、特殊索引

(1)计算列索引

计算列上的索引;

 

(2)视图索引

对视图建立索引。

一、遍历

索引树的每个节点都是一个页面。

索引树有三种类型的节点:根节点、中间节点、叶子节点。

根节点与中间节点一样,只包含下一层节点的入口值与入口指针,它们称为索引节点;

叶子节点包含要遍历的数据,对聚集索引而言数据就是表中数据行,对非聚集索引数据是指索引列值和行书签。

 

索引的遍历总是从根节点开始,即先根遍历,分为两种:索引扫描和索引查找。

索引扫描是指从索引树的根节点开始,对叶子节点逐个扫描,直至命中所有满足查找条件的数据;

索引查找是指从索引树的根节点开始,按查找值在索引节点中根据路由信息跳转,直至叶子节点以命中数据。

 

B+树的深度通常小于等于3,计算如下:

以聚集索引为例,简单计算如下:10个INT列宽度总和为40B,假设聚集索引树每一层为二叉,共三层,即2^0+2^1+2^2=1*(1-2^3)/(1-2)=7个页面,4个叶子节点,每个页面8060K可存储8060000/40=201500行,乘以4=806000行,如果是三叉、四叉,那么三层可存储上千万至亿行的数据,当然在数据量达到这个等级时,通常我们会选择表分区,那么B树深度就更不会突破三层了。

所以索引查找的效率是很高的,在查询中应该努力构造索引查找,避免索引扫描。

 

二、插入

2.1、页空间充足

在已存在数据的表上,创建或重建索引时,可指定填充因子,即在索引树的每个节点上预留一定的空间,供表中后续增加的数据使用。但如果在创建表的时候就创建了索引,并指定了填充因子,这时的填充因子是无用的,数据库系统不会刻意去保留页面的空间。

 

索引页面有剩余空间的情况如下图:

 


 图
1

参考图1,此时向索引树中插入一条索引键值为31的记录,步骤如下:

(1)执行索引键值=31的查找操作,确定该新记录应该插入到叶子节点L2中。

(2)检查L2上是否有足够的空间来存放当前记录,这里假设有足够的空间;

(3)将记录45向后移动,插入索引键值为31的新记录。插入之后,10、30、31、45还是顺序的,如下图:

图2

 2.2、页空间不足

 参加图2,此时再插入一条索引键值为32的记录,步骤如下:

(1)执行索引键值=32的查找操作,确定该新记录应该插入到叶子节点L2中;

(2)检查L2上是否有足够的空间来存放当前记录,这时发现没有足够的页空间,此时需要进行页面分裂;

(3)向数据库系统申请一个新的页面L4,将L2的一半数据移到L4中,并重新链接叶子的左右节点,如下图:

图3

(4)此时,上层节点也需要生成一个新的叶子节点的指针。这里的上层节点即根节点,如果上层节点没有剩余空间的话,同样也需要进行分裂,这里有剩余空间,如下图:

图4

(5)因为当前记录的键值范围位于页分裂的后一半中,将索引键值为32的新记录插入到L4中,如果键值范围位于前一半,则插入到L2中。如果L4的空间不够存放键值为32的新记录,则L4会继续进行页分裂,这里假设空间足够,插入结束,如下图:

图5

三、删除

3.1、删除叶子节点中的记录

参考图5,删除索引键值为32的记录,步骤如下:

(1)执行索引键值=32的查找操作,确定该记录在L4中;

(2)将索引键值=32的记录标记为虚影,但并不立即释放空间,虚影记录可用于事务回滚、多版本等;

(3)如果此时L4上的虚影记录空间被申请使用,虚影记录就会被擦除;

(4)如果数据页面最后一条记录也被删除,数据页面会被回收;

 

3.2、删除非叶子节点中的记录

(1)索引节点中的指针被删除时并不是虚影记录,但同样也不释放空间,直到有新的指针插入时,才会进行空间压缩;

(2)堆表中数据行被删除后,页空间不会被回收,即使是空闲分页也还是标识为分配状态,无法被其他对象使用;

 

注:从理论上讲,在兄弟节点页面空闲空间都小于50%时,应该将兄弟节点合并,即分裂的逆操作,但这样可能带来的后果是更频繁的页面合并、分裂,成本更大,所以在数据库系统中通常不进行页面合并操作。

 

四.更新

4.1、覆盖更新

如果更新操作能够在页内进行原位键值替换,那么就进行覆盖更新。

 

4.2、非覆盖更新

无法进行覆盖更新时,更新操作被分解为删除和插入操作。

 

如果非覆盖更新过程中,新的记录比较长,则会在页面分裂的过程中会带来数据行的移动:

(1)聚集索引的移动对非聚集索引没有影响,因为非聚集索引中存储的是聚集索引的键值,分裂并不会改变键值;

(2)堆表中的数据页分裂,会在原记录处留下一个前转指针,以告诉非聚集索引去哪里找新的记录;

所以数据行的移动对非聚集索引都不会带来维护的成本,非聚集索引的维护成本来自书签的变化:

(1)聚集索引的键值发生变化或被删除;

(2)堆表中的数据行被删除。

一、索引的作用

1、帮助检索数据;

2、提高联接效率;

3、节省ORDER BY、GROUP BY的时间;

4、保证数据唯一性(仅限于唯一索引)。

 

二、索引的设计

在确定要建立一个索引时,首先我们要确定它是聚集还是非聚集、单列还是多列、唯一还是非唯一、列是升序还是降序、它的存储是如何的,比如:分区、填充因子等。下面逐条来看:

1、聚集索引

(1)首先指出一个误区,主键并不一定是聚集索引,只是在SQL SERVER中,未明确指出的情况下,默认将主键定义为聚集,而ORACLE中则默认是非聚集,因为SQL SERVER中的ROWID未开放使用。

(2)聚集索引适合用于需要进行范围查找的列,因为聚集索引的叶子节点存放的是有序的数据行,查询引擎可根据WHERE中给出的范围,直接定位到两端的叶子节点,将这部分节点页的数据根据链表顺序取出即可;

(3)聚集索引尽量建立在值不会发生变更的列上,否则会带来非聚集索引的维护;

(4)尽量在建立非聚集索引之前建立聚集索引,否则会导致表上所有非聚集索引的重建;

(5)聚集索引应该避免建立在数值单调的列上,否则可能会造成IO的竞争,以及B树的不平衡,从而导致数据库系统频繁的维护B树的平衡性。聚集索引的列值最好能够在表中均匀分布。

 

2、非聚焦索引

(1)非聚集索引适合用于需要进行等值查找的列,因为非聚集索引的叶子节点存放的是有序的索引列与书签的映射行,查询引擎可根据WHERE中给出的值,得到书签,继而定位到数据行;

(2)覆盖索引(Covering Index),是非聚集索引的一种特殊且高效的应用,就是将需要返回的数据列设计成组合索引,在SELECT时只查询索引中存在的数据列,这样就能形成索引覆盖,因为索引行中已经包含了想到的数据,不需要再进行书签查找;

在SQL SERVER 2005及以上版本中,提供了INCLUDED关键字,可以在非聚集索引中包含更多列,也是覆盖索引的一个有效引申;

(3)非聚集索引建立在值具有单调性的列上,比如:自增列(单调递增),可以减少索引的外部碎片及索引结构的维护;

 

3、复合索引

(1)复合索引建立在多个列上。上面已经讲过,在非聚集索引中,可以利用覆盖索引来提高检索的效率,但如果组合索引的列太多的话,那么对于这个索引的维护成本也会加大,DML的效率将会下降,而且索引的查找路径会变长;

(2)在创建复合索引时,应该将高选择性的列放在前面,即作为引导列;

 

4、唯一索引

(1)再指出一个误区,聚集索引并不一定是唯一索引,由于SQL SERVER将主键默认定义为聚集索引,事实上,索引是否唯一与是否聚集是不相关的,聚集索引可以是唯一索引,也可以是非唯一索引;

(2)将索引设置为唯一,对于等值查找是很有利的,当查到第一条符合条件的纪录时即可停止查找,返回数据,而非唯一索引则要继续查找,同样,由于需要保证唯一性,每一行数据的插入都会去检查重复性;

 

5、分区索引

(1)SQL SERVER从2005引入的分区表的概念,对于在分区表上建立的索引,无论是否包含分区列,在未指定分区方案或文件组的情况下,均会使用分区表的分区方案来创建该索引。这一点与ORACLE正好相反;

 

6、其他索引

(1)筛选索引,在ORACLE中叫域索引,这是SQL SERVER 2008新增的功能,适用于表中数据密度不高的列来创建索引,比如:表中某列大多是NULL或某相同值,那么此时可通过WHERE关键字来筛选这些相同值来创建索引,这样在对非相同的值进行检索时,即可以用到这个索引;

(2)计算列索引,在ORACLE中叫函数索引,如果表中存在计算列,但想要对计算列进行检索,可在计算列上创建索引,但前提是必须要先持久化该计算列;

(3)索引视图,在ORACLE中叫物化视图,我们知道视图的数据都是来源于基础表,在SQL SERVER中对视图建立索引,事实上就对视图进行了物化,然后才创建索引,索引视图多用于静态数据的查询,毕竟物化视图的更新是比较麻烦的;

(4)位图索引,对BOOL型字段建立索引,在SQL SERVER中暂未提供这样的功能;

(5)XML索引,对XML列只能创建XML索引;

(6)全文索引,LOB类型列上无法建立普通索引,比如VARCHAR(MAX)、TEXT、IMAGE,如果需要检索可以考虑建立全文索引,当然全文索引也可以用在非LOB类型的列上;

 

7、索引参数

(1)填充因子,索引的叶子节点的填充程序,预留一定的页空间,以避免过多的页拆分,但如果预留空间太大,会放大查询的成本。对于索引的中间节点如果也使用填充因子可以打开PAD_INDEX选项;

(2)忽略重复键,这个选项通常用于去重处理,对于将要插入到表中的行,如果存在相同索引键,则抛弃;

(3)根据业务查询需要,决定列升序还是降序,通常对于单列索引存在正向或反向扫描,但在复合索引的非引导列中检索时,如果存在需要倒排的查询,则在建立索引时应选择降序;

(4)在索引的存储上,将聚集和非聚集索引定义在不同磁盘分区的文件组上,减少IO竞争,亦可利用多CPU并发,但目前通常都是RAID5+1(1备份5中的一块硬盘)的存储,数据存放本就已分散,这样做的意义并不是太大。

 

8、索引列选择

(1)参考[索引的作用]选择索引列,比如:如果表中存在外键,考虑在该列上建立索引,可增加参照完整性检查的速率,同样,如果存在连接,也可提高连接的速率;

(2)索引选择性公式:selectivity=unique keys/rows,一般当选择性低于0.1即10%时,查询优化器拒绝使用该索引,比如:BOOL类型的列。此处有一个矛盾,有可能我们无法知道当前列的selectivity,那么只能采用估算的方式,比如采用SQL SERVER 2005的TABLESAMPLE进行数据采样等;

(3)在面对一个多条件的查询时,应该选择过滤性较强的字段作为单列索引,或作为复合索引的引导列;

(4)在长度较小的数据类型上建立索引,这样每条索引存储所占用的空间就会变小,每个索引页上就能够存储更多的索引行,缩短索引查找的路径;

(5)不要在一个表上建立太多的索引,索引的维护会影响DML的效率;

 

三、索引的使用

1、避免无效搜索表达式

(1)WHERE条件中将索引列放在表达式中:如fun(c1) = 1,c1+c2 = 2等;

(2)索引列在未知数值起点的LIKE运算符中:如Like ‘%abc’或like ‘%abc%’;

(3)包含否定运算符的表达式,如:<>、not in/exists/like;

(4)NULL表达式,如:is null、is not null;

总之,无法让检索值与索引值,进行比较运算的表达式,都为无效搜索表达式。

 

2、复合索引的引导列

比如复合索引列为(c1,c2,c3),则在WHERE条件中必须指定c1,才会用到该复合索引;

 

以上两点总的原则就是:构造索引查找,避免索引扫描,我们通常所说的:能不能用到索引,也应该是指索引查找,而不是索引扫描。

 

3、尽量使用等值运算符

比如在使用WHERE c1>1时,SQL SERVER会尽量去将它转会为WHERE c1>=2(如果整形的话),以给索引查找一个起点,如果无法隐式转换为>=,则会以c1>=1为起点,查找完成后再踢除=1的数据;

 

4、表达式的顺序

在WHERE条件中包含多个表达式时,应该将过滤性最强的表达式放在靠近WHERE的位置,通常这样的表达式中的列,也会选择在上面建立索引,因为在一个WHERE子句中只有一个表达式是可以使用索引的,其他的表达式都是基于索引查找结果集的过滤,所以应尽量保证有效索引的使用。尽管查询优化器会去识别,然后自动去重排表达式的顺序,但我们应该养成一个好的习惯。

 

一、索引碎片

无论是索引组织表(IOT)还是堆表(HEAP),随着数据的增删改,都会或多或多的产生碎片。碎片的存在,主要对于数据扫描效率有着较大的影响,对于数据查找效率几乎没有影响或者说影响很小,如果想要改善数据查找的效率,进行索引碎片整理并没有什么效果。以下的碎片分类也主要是从数据扫描着眼。

1、内部碎片

内部指的是页内,即页面的空闲空间。其实填充因子就是一种碎片,为了减少页拆分,宁愿适当地去制造这种碎片。但在大量内部碎片一直处于无法被数据填充的情况下,是没有益处的,它会导致扫描过程中读取额外的页面。

对于LOB和ROW_OVERFLOW_DATA页面,这是唯一的碎片形式,因为在这两种列上无法建立B树索引。

 

2、外部碎片

(1)逻辑碎片

索引叶子节点页的逻辑顺序与物理顺序不一致,比如:有页号1,2的两个页面,此时1页面发生页拆分,这时新申请的页面页号为3,此时逻辑顺序为1-3-2,但物理顺序是1-2-3,1页面没有直接指向磁盘的下一个物理页,这就造成了不一致,即逻辑碎片;

 

(2)扩展碎片

SQL SERVER通常给表或索引分配新的空间是以EXTENT(区或扩展)的形式,一个区是8个页面,所以区的第一个页号应该是8的倍数,比如:一个包含有序区的表,第一个页面的页号应该是8-16-24,这样下去,如果是8-24,那么说明第一个页面页号为16的区被分配给了另一个表,那么8-24的表在物理上就存在一个间隙,即扩展碎片;

 

外部碎片是对数据连续性的度量,扩展碎片是堆表数据连续性的度量,数据的连续性越差,扫描的成本也会越大。

 

二、查看与管理

对于索引树的管理主要考虑两方面:一是B树的平衡性,这一点数据库系统会自动维护;二是索引碎片,这需要手动去维护。

1、碎片的查看

SQL SERVER支持两种碎片查看方式,至于这两种碎片查看方式的使用方法,帮助文档里有很详细的说明。

(1)dbcc showcontig是SQL SERVER 2000中的唯一碎片查看方式,在SQL SERVER 2005中无法支持LOB类型、ROW_OVERFLOW_DATA及整个分区表的碎片查看;

 

(2)sys.dm_db_index_physical_stats是SQL SERVER 2005新的碎片查看方式;

 

对于碎片的检测以及是否需要进行碎片处理,主要从以下几个参数来看:

(1)内部碎片检测

avg_page_space_used_in_percent:页面空间平均使用比例;

对于数据扫描而言,该参数越大越好,这意味着读取较少的页面即可返回想要的数据。

 

fragment_count:IN_ROW_DATA碎片的数量;

avg_fragment_size_in_pages:IN_ROW_DATA碎片的平均页大小;

以上参数反应了行内数据页碎片的数量及碎片的大小,即便碎片数量很多,但如果碎片很大即很整块的话,通常要大于64KB即一个EXTENT,对于数据扫描而言,效率也是很高的,因为SQL SERVER会跳过这些整块的碎片。

 

ghost_record_count和version_ghost_record_count:虚影纪录数;

对于数据扫描而言,该参数越小越好。

 

forwarded_record_count:前转纪录数;

前转纪录只会在堆中存在,对于数据扫描而言,是非常有帮助的。

 

(2)外部碎片检测

avg_fragmentation_in_percent:页面平均外部碎片的比例;

对于数据扫描而言,该参数越小越好。

 

2、碎片的整理

(1)、索引重建

顾名思义,重新建立索引,对索引的数据进行重新排列。在SQL SERVER 2000中这是一个脱机操作,即索引重建完成前,索引无法访问或使用,在SQL SERVER 2005/2008中支持联机操作。

 

联机过程的实现,就是先维护另一份新索引,然后同步旧索引中变化的部分,同步完成后使用架构锁锁定旧索引,切换表到新的索引上,再释放架构锁,切换的过程是数据库系统目录的维护过程,速度很快,所以可以理解为是联机操作。

 

索引重建的方式有四种:

A:drop index再create index

这种方法是最差的,它会导致表上非聚集索引的两次重建,一次在DROP时指向ROWID,一次在CREATE时重新指向聚集键。以下三种方法只需重新非聚集索引一次。

而且对于主键约束或唯一键约束产生的索引无法直接删除,必须要先删除约束,才可以删除索引;

 

B:create index的drop_existing选项

这种方法完全重建索引,并可以重新指定索引参数;

 

C:alter index的rebuild选项

这是SQL SERVER 2005/2008新的重建索引的方式,它不会重建非聚集索引,除非指定ALL关键字,同时它也更灵活,可以针对表上某个分区重建索引;

 

D:dbcc dbreindex;

这是SQL SERVER 2000时重建索引的方法,它默认使用表上原来create index的参数重建索引。填充因子可重新指定。

 

(2)、索引重组

将索引树的叶节点页重新排序,以消除外部碎片。这是一个联机操作。但不同于索引重建的是,索引重组后统计信息不会得到更新,而且索引重组使用的是冒泡排序法,效率比较低。同时,索引重组只能在单个文件内进行,无法跨文件重组索引。

 

索引重组的方式有两种:

A:alter index的reorgnize选项

这是SQL SERVER 2005/2008新的重组索引的方式,和dbcc indexdefrag一样,它默认对表上所有分区进行索引重组,不可以重新指定填充因子,因为只是索引叶子节点的重新排序。但它比dbcc indexdefrag的选项更丰富些;

 

B:dbcc indexdefrag

这是SQL SERVER 2000时重组索引的方法。

 

注意:

(1)碎片是不可避免,但并不是说一旦检测到碎片就进行碎片整理,有时少量碎片的整理工作反而会带来更大的成本消耗,所以在不能确定索引整理能否带来良好性能时,不要轻易进行索引整理。

(2)不管是内部碎片还是外部碎片,即便进行了碎片整理,也并不一定能够完全消除,对于外部碎片,可以将表独立存放在一个文件组上,并在文件初始化时分配足够的磁盘空间,这样的表经过碎片整理后外部碎片可以消除,但太过浪费磁盘空间;

(3)无论是索引重建、索引重组都会对数据页进行压缩,页面的填充程度由填充因子决定。它们都是事务操作,会产生日志,为了减少事务日志的大小,可在索引整理后进行日志截断或日志备份。

(4)如有必要,对于DML非常频繁的表,为了保证数据扫描的效率,可以考虑利用作业来在系统相对空闲的时候定期进行索引整理

 

物理结构的设计,也即是设计数据在磁盘上的存储,需要考虑:如何做到安全、IO竞争少、服务器资源利用率高。

 

通常当前数据库只使用一份ONLINE的数据源,至于分布式存储已经上升到服务器架构的设计,这里不作讨论。以下仅简单描述非分布式存储的情况,主要从磁盘、文件、表数据三方面来说。

一、磁盘

RAID0提供了最好的读写性能,但RAID0没有提供冗余恢复策略,所以很少单独全用。通常,使用RAID10或RAID5来实现磁盘数据的存储与容灾。

 

随着磁盘上数据量的提升,RAID5的读写性能会明显低于RAID10,RAID5至少需要3块磁盘,RAID10至少需要4块磁盘,RAID5在同样提供数据容灾的情况下,更能节省成本,但如果成本不在考虑范围内,当然是性能优先,使用RAID10。

 

二、文件

2.1、文件组(表空间)

在SQL SERVER中叫文件组,在ORACLE中叫表空间,它们都是对数据文件的逻辑分组。使用文件组的目的如下:

(1)性能

文件组中的文件放在不同磁盘上,是否可以提高读写的效率?在使用RAID1或RAID5的情况下,这种效率的提升已经几乎可以忽略,因为数据本身已经被分散写到RAID上的各块磁盘上;

 

(2)管理

目前使用文件组的目的,大都出于管理。

a)在磁盘空间不足的情况下,可以使用多个小空间的磁盘,同时,也可为数据库扩展新的磁盘空间;

b)备份/还原,只读/读写,离线/在线等数据库管理与维护;

 

SQL SERVER中文件组与文件的关系如下图:


 

 



  

2.2、文件

(1)如果文件组中的文件被限制大小,文件填满了会不会自动新建一个文件?

不会,那么此时数据库会报出空间不足的错误,所以在定义文件时,要么指定其大小无限增长(直到填满磁盘空间),要么定期检查文件空闲空间的大小,以手动扩展。

 

(2)文件组中文件是一个个写入还是各个文件同时都在增大?

SQL SERVER中是文件级别中各个文件同时写入,ORACLE中是写满一个再写下一个。

 

三、表数据

3.1、堆表和索引组织表

使用堆表还是索引组织表,取决于对DML效率的要求。

(1)堆表在DML时没有聚集索引的维护成本,在非明确指定的情况下,ORACLE中默认使用堆表;

(2)对于主键的单值或范围查找,尤其是范围查找,索引组织表效率更高,因为省去了bookmark lookup的成本,在非明确指定的情况下,SQL SERVER中默认使用索引组织表。

 

关于堆表和索引组织表的设计,详见《SQL Server 查询优化》系列。

 

3.2、表数据分割

数据分割的方式,通常可分为以下两种:

3.2.1、水平分割

出于读写性能的考虑,将一个大表,拆分为若干个小的单元,应用程序根据每个单元的入口规则,映射到相应的单元,只处理所需访问的单元中的数据,以提高数据读写的效率。

 

水平分割针对表中数据行进行分割,可采用以下方式:

(1)分表

在还没出现分区的概念时,对于大表,通常采用分表的方式来实现数据的水平分割。

 

按照一定的规则将数据分别存入不同名称的表中:

a)最常见的就是按日期、时间来分表,比如:将每月的订单放到当前月的订单表中,orders_201001、orders_201002、orders_201003……依次类推;

 

b)也可以根据编号规则来分表,比如将尾数:将订单尾数为1的订单放到一个表中,orders_1、orders_2、orders_3……依次类推;

 

(2)表分区

a)SQL SERVER 2005以前的版本中,出现过分区视图,算是它在分区表出现前的一个替代品,有本地分区视图和分布式分区视图两种。分布式分区视图的概念,倒是有现在分布式存储的味道,但由于受网络因素影响较大,未被广泛使用。

 

b)对于本地化的表分区,目前多采用分区表,结构如下图:

 

3.2.2、垂直分割

垂直分割针对表中列进行分割。

如果表中列非常多,从而导致一行数据所占用的存储空间非常大时,可以考虑进行垂直分割,比如:将一个表拆成主表和从表,主表中存放访问最频繁的列,从表中存放访问较少的列,从而提高数据读取的效率。

 

通常不建议使用垂直分区,如果主从表都变得很大,在需要进行主从表关联时,成本也是相当高的,可能会影响性能。

 

3.3、簇

簇(CLUSTER),这是ORACLE里的一个概念,将多个表中相同的字段存放到一起,称为簇,即聚集的意思,这里需要和聚集索引的概念区分开来。放到一起的好处如下:

(1)节省存储空间,相同数据只需要存一份;

(2)提高多表关联的速度;


基于stm32平台上的IC-MU磁绝对值编码器SPI通讯和码盘数据处理 阅读详情

相关推荐

Localizing LabVIEW Application to Different Languages

本文探讨了LabVIEW应用程序的多语言本地化实现方案。文章首先分析了LabVIEW对多语言的支持现状,指出其默认仅支持ANSI编码,对Unicode支持有限,且仅适配中英法德日韩六种语言。然后重点介绍了JKISimpleLocalization工具包的使用方法,该工具能导出/导入JSON词典文件,实现界面语言的实时切换。文章还结合实际工程案例,分析了该方案的局限性:部分控件不可翻译、切换速度较慢(33个界面需50秒)、小语种支持不足等。最后提供了完整的应用流程和工具包附件,包括词典文件转换工具和工程案例。

2301_80383260的博客 1407

智能插座本地化改造:刷开源固件接入Home Assistant实现毫秒级响应

在物联网和智能家居领域,设备联网与控制是核心基础。传统云控方案依赖远程服务器中转指令,存在延迟高、隐私泄露和断网失效等问题。其技术原理在于设备固件与云端协议绑定,导致控制链路必须经过公网。为解决此痛点,本地化控制技术应运而生,它通过MQTT等轻量级协议在局域网内直接通信,实现了极低延迟、高可靠性与数据自主。这项技术的核心价值在于将设备控制权彻底交还用户,构建真正私有、快速的智能家居系统。其典型应用场景包括智能照明、安防传感及家电控制等需要实时响应的环节。本文聚焦于利用开源固件对基于BK7231芯片的智能插座

weixin_30376083的博客 365

DL-FWI基础入门培训视频学习1、2

DL-FWI基础知识

shengMio的博客 708

sql server高级知识梳理二:索引知识梳理

索引: 1.所有出现字段的地方都可以用到索引,包括 select后,where后,group by后,order by 后。 2.数据结构为b+树,对比平衡树:b+树深度浅(一般不会大于4层)查询速度更快 对比 b树: B树所有节点都带有数据,每一层可存放的索引少于B+树,导致需要更多层的中间节点。数据量大的的时候查询更慢。 B+树所有数据在叶子节点,并且叶子节点的数据有指针指向下一条数据,所以当查询范围数据是,B+树更快。 3.分为聚集索引和非聚集索引 聚集索引 1)聚集...

qq994877603的博客 582

PMAC上位机通信原理(C#)

基础是引用 两个 ODT dll 原理是先注册到communication.AsyncDataAvailable事件中去 if (bSuccess1) { communication.AsyncDataAvailable += communication_AsyncDataAvailable; } bool bSuccess2 = communication1.GPAsciiConnect(strIP, iPort, strName, strPassword); i

weixin_45507349的博客 1086

MAX31856高精度热电偶测温系统实战:从寄存器配置到温度读取

本文详细介绍了MAX31856高精度热电偶测温系统的实战应用。从硬件连接避坑、核心寄存器配置(如CR0、CR1),到利用中断高效读取并解析温度数据,提供了完整的驱动框架和代码示例。该方案解决了传统热电偶信号微弱、非线性及冷端补偿难题,适用于工业测温等场景,帮助开发者快速实现稳定可靠的高精度温度测量。

coffee的博客 483

sqlserver数据库索引深解

数据库数据基本单位是页插入数据,是看当前页有没有空间,如果有的话,就在当前页插入数据,没有空间了,就新建页(比较耗时)对于有聚集索引的表,存在从中间插入数据,比如id列为1,5,7,8,我要插个6进去,就可能要重新排列页里面的数据,这个问题可以用填充因子来解决,填充因子就是每个页每行数据空出点空间,用来插入新数据,当然有填充因子的话,要多耗一些磁盘空间.8个连续页为一个区http://msdn.m

zb219的专栏 581

SIwave仿真手册——信号完整性仿真之S参数的提取(二)

上一篇简单了讲述了软件的各个操作界面,本次博客更新关于的仿真,因为第二章完整的内容比较多,所以分成好几篇博客进行分享。

luohuo9844的博客 1万+

Sql server索引优化

Sql server索引优化

胡杰的专栏 5811

OpenClaw与Ollama本地AI部署指南

AI模型本地化部署是当前企业数字化转型的关键技术,通过开源框架Ollama可以在消费级硬件上运行大语言模型。本文以OpenClaw多智能体系统为例,详解从环境配置到模型优化的全流程实践,特别针对国内开发者遇到的网络问题提供了镜像加速等解决方案。这种私有化部署方案尤其适合金融数据分析、企业知识管理等对数据安全要求高的场景,通过模块化设计实现多智能体协作,同时保持对NVIDIA显卡和普通CPU的兼容性。

weixin_34302561的博客 396

2026年数学建模国赛C题利器:层次分析法与主成分分析在统计建模中的应用

本文系统探讨了层次分析法(AHP)与主成分分析(PCA)在数学建模竞赛,特别是全国大学生数学建模竞赛C题中的联合应用策略。通过理论阐述、方法对比和案例实践,本文揭示了两种方法从“数据降维”到“决策评价”的完整分析链条,提出了“PCA+AHP”协同框架,并通过实际算例验证了该框架在解决复杂评价类问题中的有效性和优越性。研究表明,将PCA的客观降维能力与AHP的主观决策优势有机结合,能够显著提升统计建模的科学性、合理性和解释力,是应对日益复杂的竞赛题目的重要方法论工具。关键词:层次分析法;主成分分析;数学建模。

YOLO 40

SQL Server中的索引内部结构:到SQL Server索引级别10的阶梯

原文链接:http://www.sqlservercentral.com/articles/Stairway+Series/72442/ SQL Server中的索引内部结构:到SQL Server索引级别10的阶梯 By David Durant, 2012/01/20 该系列 本文是楼梯系列的一部分:SQL Server索引的阶梯 索引是数据库设计的基础,并且告诉开发人员...

weixin_34313182的博客 176

电子电器架构 --- OEM企标中规定ECU启动时间的目的

电子电器架构 --- OEM企标中规定ECU启动时间的目的

Soly_kun的博客 223

SQL Server 查询优化(1)_索引的结构与分类

一、索引的结构关系型数据库中以二维表来表达关系模型,表中的数据以页的形式存储在磁盘上,在SQL SERVER中,数据页是磁盘上8k的连续空间,那么,一个表的所有数据页在磁盘上是如何组织的呢?分两种情况:一是数据页间无序、随机地存储在磁盘上,这样的表叫做堆表;二是数据页间按某个表字段的值有序地存储在磁盘上,这样的表做索引组织表。 索引是什么?从物理结构上可分为两种:聚集索引和非聚集索引。

张骞 1758

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

SQL Server 查询优化之一_索引的结构与分类

一、索引的结构关系型数据库中以二维表来表达关系模型,表中的数据以页的形式存储在磁盘上,在SQL SERVER中,数据页是磁盘上8k的连续空间,那么,一个表的所有数据页在磁盘上是如何组织的呢?分两种情况:一是数据页间无序、随机地存储在磁盘上,这样的表叫做堆表;二是数据页间按某个表字段的值有序地存储在磁盘上,这样的表做索引组织表。索引是什么?从物理结构上可分为两种:聚集索引和非聚集索引。将表中的数据有序地组织起来的索引称为聚集索引,一个表只有一个聚集索引,表上其他的索引都是非聚集索引。1.1、聚集索引结构(1)

Donald_Pan的专栏 525

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

SQL Server查询优化

看过一篇文章,印象深刻,里面将数据库查询优化分为四个大的方向使用钞能力——给DB服务器加物理配置,内存啊,CPU啊,硬盘啊,全上顶配替换存储系统——根据实际的业务情况选择不同的存储数据库,比如用ES做全文检索优化存储结构——比如采用分库分表,CQRS(命令查询职责分离),分布式缓存,历史数据归档,数据序列化等查询语句的优化——增加数据库索引命中率,定期清理数据库索引碎片等从上到下成本依次递减,性价比依次升高,今天咱们聊聊Sql Server中基于索引的“查询语句的优化”...

萌兔兔MMQ!! 372

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

SqlServer索引的原理与应用

原文:SqlServer索引的原理与应用索引的概念 索引的用途:我们对数据查询及处理速度已成为衡量应用系统成败的标准,而采用索引来加快数据处理速度通常是最普遍采用的优化方法。 索引是什么:数据库中的索引类似于一本书的目录,在一本书中使用目录可以快速找到你想要的信息,而不需要读完全书。在数据库中,数据库程序使用索引可以重啊到表中的数据,而不必扫描整个表。书中的目录是一个字词以及各字词所在的页码列...

weixin_34343689的博客 255

SQL Server 和 Azure SQL 索引体系结构和设计指南

SQL Server 和 Azure SQL 索引体系结构和设计指南

zyypjc的博客 2089

SQL sever中的索引

SQL sever中的索引

m0_71406734的博客 6801

sqlserver 索引的结构及其存储

正好想了解,查了一下,做个记号。 文章转载,原文地址: http://www.cnblogs.com/panchunting/p/SQLServer_IndexStructure.html 本文关注以下方面(本文所有的讨论基于SQL Server数据库): 索引的分类;索引的结构;索引的存储 一、索引定义分类   让我们先来回答几个问题:   什么是索引?

哈哈哈哈哈哈 2045

SQL 实战—递归 SQL:层级结构查询与处理树形数据

递归 SQL 是指在 SQL 查询中,

2509_93994560的博客 451

SqlService 索引原理

索引的概念 索引的用途:我们对数据查询及处理速度已成为衡量应用系统成败的标准,而采用索引来加快数据处理速度通常是最普遍采用的优化方法。 索引是什么:数据库中的索引类似于一本书的目录,在一本书中使用目录可以快速找到你想要的信息,而不需要读完全书。在数据库中,数据库程序使用索引可以重啊到表中的数据,而不必扫描整个表。书中的目录是一个字词以及各字词所在的页码列表,数据库中的索引是表中的值以及各值存储...

weixin_30398227的博客 83

Sql Server专题一:索引(上)

写在前面的废话:索引问题已经是老生常谈的问题,虽然被经常说起,但作为我来说,至今没有用过索引(很可怕吧),我作为MS-BI实施工程师居然没用过索引,说话自然没底气。之前对索引的了解停留在“知道”的地步上,随着时间的流逝感觉不真正将索引应用起来简直是渣渣!废话到此为止,开始索引专题,为了彻彻底底(我不是DBA,能将索引理解达到熟练使用即可,所以并不彻底)搞懂索引,从数据页学习吧!本篇主要来源MS的联...

weixin_30463341的博客 141
上一篇: SQL Server2008存储结构之堆表、行溢出 、页结构、记录结构
下一篇: SQL 获取连续编号中断号的最小值
wangjunhe
博客等级 码龄20年 31粉丝 22原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值