索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以。但是索引对于提高查询性能也不是万能的,也不是建立越多的索引就越好。索引建少了,用WHERE子句找数据效率低,不利于查找数据。索引建多了,不利于新增、修改和删除等操作,因为做这些操作时,SQL SERVER除了要更新数据表本身,还要连带地立即更新所有的相关索引,而且过多的索引也会浪费硬盘空间。因此要建得恰到好处,这就需要经验了。

一:索引的基本目的

索引的基本目的是在大量数据中找寻少量数据。你可以想像一下,若一本书有700页,就像数据表有700个数据页,而索引却有600个索引页,你会想用索引来查询书籍的内容吗?

索引字段的值重复性越低越好,假设书籍中如“的”“了”这些在文章中重复性极高的字,每页都有一大堆,你会先翻索引页某个位置有“的”,翻回该页读取了“的”之后,再索引看下一个“的”,结果是在先前同一页的不同位置,又翻回书籍原页查看下一个“的”。

那么怎么理解索引是从大量数据中寻找少量数据呢?下面我们举个例子来说明。

如果一个数据表的记录平均长度为400字节,则100万条记录需要5万个数据页,其计算公式如下:

  1000000/(8060/400)=50000

  如果该数据表建立聚集索引,键值为4个字节长度,而ID的数据长度为13个字节,因此索引结构每条记录为20个字节。

  4(聚集索引键值)+13(ID键值)+3(管理信息)=20

  以ID字段所建立的索引,100%填充率,则总分页数约为2482页,其计算方式如下:

  1000000/(8060/20)

  即使是使用80%的填充率来计算也只有3106页。其计算方式如下:

  1000000/((8060*0.8)/20)

  从上面可以看出如果是第一种情况,则索引页只占到总数据页的5%:

  2482/50000=0.04964

  即使考虑取每页只填充80%的索引数据,第二种情况,索引页也只是占总数据页的6%:

  3106/50000=0.06212

  再说如果查询条件中的字段建立索引,则由于索引键值数据都是以B-Tree有顺序的摆放,所以可采用二分查找找数据。也就是2的N次方大于记录数,就可以找到该条数据。而2的20次方大于100万,因此最多找寻20次就可以找到该条记录。由于比较次数少,数据结构也小,节省访问硬盘与内在的资源,索引将大幅提升找寻数据的效率。SQL SERVER为提高访问与查找对比的效率,用来作索引的数据域键值愈小愈好,也就是要让分页尽量存更多的键值记录。

注:

  如果未使用 UNIQUE 属性创建聚集索引,数据库引擎将向表自动添加一个 4 字节的 uniqueifier 列。必要时,数据库引擎将向行自动添加一个 uniqueifier 值以使每个键唯一。此列和列值供内部使用,用户不能查看或访问。

二:什么是索引

  在 SQL Server 中,索引是按 B 树结构进行组织的。如下图。

  

  您也可以把索引理解为一种特殊的目录。微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引、簇集索引)和非聚集索引(nonclustered index,也称非聚类索引、非簇集索引)。下面,举例来说明一下聚集索引和非聚集索引的区别:

  其实,新华字典的正文本身就是一个聚集索引。比如,我们要查“按”字,就会很自然地翻开字典的前几页,因为“按”的拼音是“an”,而按照拼音排序的新华字典是以英文字母“a”开头并以“z”结尾的,那么“按”字就自然地排在字典的前部。如果您翻完了所有以“a”开头的部分仍然找不到这个字,那么就说明新华字典中没有这个字;同样的,如果查“招”字,那也会将新华字典翻到最后部分,因为“招”的拼音是“zhao”。也就是说,新华字典的正文部分本身就是一个目录,您不需要再去查其他目录来找到您需要找的内容。我们把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。

  如果您碰到一个不认识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,而需要去根据“偏旁部首”查到您要找的字,然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序并不是真正的正文的排序方法,比如您查“张”字,我们可以看到在查部首之后的检字表中“张”的页码是672页,检字表中“张”的上面是“驰”字,但页码却是63 页,“张”的下面是“弩”字,页面是390页。很显然,这些字并不是真正的分别位于“张”字的上下方,现在您看到的连续的“驰、张、弩”三字实际上就是他们在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字,但它需要两个过程,先找到目录中的结果,然后 再翻到您所需要的页码。我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。

通过以上例子,我们可以理解到什么是“聚集索引”和“非聚集索引”。进一步引申一下。

聚集索引

  聚集索引指的是数据表本身就是索引的一部分,就是指数据表本身就是聚集索引的子叶层,整个数据表的摆放顺序是按照你选定的键值由小到大排序,SQL SERVER  2000 之后的版本可指定数据由大到小排序。

  整个数据表按照键值字段由小到大排序,再搭配由键值字段加上指针的上层索引结构,也就是根节点和非子叶层级,形成整个聚集索引。因为数据表内实际摆放数据的方式只能遵循一种顺序,所以一个数据表只能有一个聚集索引。在指定聚集索引时,数据域本身并不需要唯一,或指定为唯一的聚集索引,SQL SERVER内部会自动为重复的键值建立4个字节的唯一标识。

  如果你的数据表有一列常常用来排序,另一列常常用来 范围查询,还有一列重复性非常高,则该用哪一列来做聚集索引。正确答案是依据哪个查询最重要,最常被用户执行。例如:你的老板一小时内多次执行某个查询当然比一个月执行一两次的查询来得重要。

  表(堆)创建聚集索引或删除和重新创建现有聚集索引时,要求数据库具有额外的可用工作区来容纳数据排序结果和原始表或现有聚集索引数据的临时副本。

  当堆或聚集表具有多个分区时,每个分区都有一个堆或 B 树结构,其中包含该指定分区的行组。例如,如果一个聚集表有 4 个分区,那么将有 4 个 B 树,每个分区一个。

  聚集索引( Clustered Index)

  ·        聚集索引的叶节点就是实际的数据页

  ·        在数据页中数据按照索引顺序存储

  ·        行的物理位置和行在索引中的位置是相同的

  ·        每个表只能有一个聚集索引

  ·        聚集索引的平均大小大约为表大小的 5%左右

  要使用索引来更有效地排序查询数据,最直接的方式就是在你要排序的字段上建立聚集索引。在建立聚集索引之后,SQL SERVER会重新组织数据页,让其中的数据行按照聚集索引中键值的顺序存储。SQL SERVER不需要在硬盘上的数据一定要实际按照聚集索引排序,但在建立聚集索引时,会尝试在逻辑上排序数据的同时,也会在物理上让数据尽可能地排序。在索引子叶层级中的每个数据页都有一个指针指向索引分页的前一页与后一页,形成双向链接串行,在内部的系统数据表包含了各索引子叶层第一个分页的地址,为了保证数据在逻辑上是依照聚集索引的顺序存放的,SQL SERVER 只需要由第一个分页开始,并依照其连接串行一个接着一个依序寻找数据即可。如下图。

注:聚集表是有聚集索引的表。

非聚集索引

  非聚集索引是完全独立于数据表之外的结构,所以不会影响数据行的顺序,其子叶层包含索引行。每个索引行包含非聚集键值、行定位符和任意包含列或非键列。行定位符中存入的数据有两种类型:书签(BOOKMARK)或聚集索引的键值。如果数据表上建立了聚集索引,则行定位符中存入的数据就是聚集索引的键值。如果数据表没有建立聚集索引,则行定位符中存入的数据就是书签,即指向数据表中记录具体位置的ROWID,也就是文档编号、分页编号与页内记录编号(称之为SOLT编号)所组合成的值。通过该ROWID 在数据表内获取数据就称为书签查找 BOOKMARK LOOKUP。所以,一般通过非聚集索引查找到符合的键值后,还会搭配书签查找。

  当非聚集索引从结构中找到符合的记录时,虽然在子叶层该键值是由小到大排序,因此可能在一个分页上就有全部符合查询条件的键值,但因为数据表中数据行的摆放是没有按顺序的(或是说没有按照该非聚集索引的键值顺序摆放),所以真正符合记录的数据是散布在文档各处的,而SQL SERVER每次读取数据都是以数据页为单位,因此,找到一条记录所在位置后,要先将存放该条记录的分页读到内存中,再从该页读出记录。

  因为BOOKMARK LOOKUP是进行随机的I/O操作,当符合查询的记录很多时,通过非聚集索引访问将导致数据页读取非常频繁,就算两条记录在同一个分页,该分页也会被重复读两次,因此或符合的记录有N条,就需要读取数据表内的分页N页,虽然大部分的读取操作都是针对内存中的高速缓存,但记录数过多时一样没有效率,还不如数据表扫描,全部扫描一遍,把符合条件数据找出来。

  虽然 SQL 2005 以后的版本中已经不在提 BOOKMARK LOOKUP了(但实际上却是换汤不换药),我们的很多搜索都是使用如下的搜索过程:先在非聚集中找,然后再在聚集索引中找。如下图。

  非聚集索引 ( Unclustered Index)

  ·        非聚集索引的页,不是数据,而是指向数据页的页。

  ·        若未指定索引类型,则默认为非聚集索引

  ·        叶节点页的次序和表的物理存储次序不同

  ·        每个表最多可以有 249个非聚集索引(一般认为每个表不应该超过10个索引)

  ·        在非聚集索引创建之前创建聚集索引(否则会引发索引重建)

  聚集索引与非聚集索引使用的情况:

动作描述

使用聚集索引

使用非聚集索引

外键列

主键列

列经常被分组排序(order by)

返回某范围内的数据

不应

小数目的不同值

不应

大数目的不同值

不应

频繁更新的列

不应

频繁修改索引列

不应

一个或极少不同值

不应

不应

  今天就普及一下索引的一些基本知识,明天来说明怎么选择要创建索引的列,条件是什么,方法是什么。

SQL Server 查询性能优化——创建索引原则(一)的更多相关文章

  1. SQL Server 查询性能优化——创建索引原则

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...

  2. SQL Server查询性能优化——创建索引原则(一)

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页 就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索 ...

  3. SQL Server 查询性能优化——创建索引原则(一)(转载)

    索引是什么?索引是提高查询性能的一个重要工具,索引就是把查询语句所需要的少量数据添加到索引分页中,这样访问数据时只要访问少数索引的分页就可以.但是索引对于提高查询性能也不是万能的,也不是建立越多的索引 ...

  4. SQL Server 查询性能优化——创建索引原则(二)

    三:索引的建立原则 一般来说,建立索引要看数据使用的场景,换句话来说哪些访问数据的SQL语句是常用的,而这些语句是否因为缺少索引(也有可能是索引过多)变的效率低下.但绝不是所有的SQL语句都要建立索引 ...

  5. SQL Server查询性能优化——覆盖索引(二)

    在SQL Server 查询性能优化——覆盖索引(一)中讲了覆盖索引的一些理论. 本文将具体讲一下使用不同索引对查询性能的影响. 下面通过实例,来查看不同的索引结构,如聚集索引.非聚集索引.组合索引等 ...

  6. SQL Server 查询性能优化——覆盖索引

    覆盖索引又可以称为索引覆盖. 解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖. 解释二: 索引是高效找到行的一个方法,当能通过检索索引 ...

  7. SQL Server查询性能优化——覆盖索引(一)

    覆盖索引又可以称为索引覆盖. 解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖. 解释二: 索引是高效找到行的一个方法,当能通过检索索引 ...

  8. SQL SERVER 查询性能优化——分析事务与锁(五)

    SQL SERVER 查询性能优化——分析事务与锁(一) SQL SERVER 查询性能优化——分析事务与锁(二) SQL SERVER 查询性能优化——分析事务与锁(三) 上接SQL SERVER ...

  9. SQL Server 查询性能优化 相关文章

    来自: SQL Server 查询性能优化——堆表.碎片与索引(一) SQL Server 查询性能优化——堆表.碎片与索引(二) SQL Server 查询性能优化——覆盖索引(一) SQL Ser ...

随机推荐

  1. redis连接错误处理方案分享

    今天为了搞压测,定位是不是redis瓶颈. 在我们的服务器10.90.2.101上安装了一个redis,版本(redis-3.2.8.tar.gz),没有做任何配置,直接make & make ...

  2. Delphi常用API,API函数

    auxGetDevCaps API 获取附属设备容量 auxGetNumDevs API 返回附属设备数量 auxGetVolume API 获取当前卷设置 auxOutMessage API 向输出 ...

  3. Delphi XE5的Android开发平台搭建[转]

    Delphi XE5支持Android ARM的开发,可以在Android虚拟机里运行,因此建议将XE5安装在64bit的Windows,内存可以大于3GB Delphi XE5安装光盘中包含了最基本 ...

  4. 【转】SQL Server日志文件过大 大日志文件清理方法 不分离数据库

    https://blog.csdn.net/slimboy123/article/details/54575592 还未测试 USE[master] GO ALTER DATABASE 要清理的数据库 ...

  5. BlueZone automation note1

    To run the patch test cases in C:\sliData\TAF\bzw\test-packs\run_jobs via run_example_tests_smoke_te ...

  6. 记一次包含iframe的需要滚动的元素不能滚动到底部的问题

    一个包含上头部.下部模块(包含左右两边模块:侧边栏.内容区域)的页面 前提条件,内容区域: 1.元素高度需要自适应屏幕高度 2.里面内容足够长时,可以滚动 3.包含了一个iframe嵌入的内容很长的页 ...

  7. http_range说明

    100-200 // 第100到第200字节 500- // 第500字节到文件末尾 -1000 // 最后的1000个字节

  8. 【IIS错误】IIS各种错误

    IIS简介 当用户试图通过HTTP或文件传输协议(FTP)访问一台正在运行Internet信息服务 (IIS)的服务器上的内容时,IIS返回一个表示该请求的状态的数字代码.该状态代码 记录在IIS日志 ...

  9. flume使用之httpSource

    flume自带很长多的source,如:exe.kafka...其中有一个非常简单的source——httpsource,使用httpSource,flume启动后会拉起一个web服务来监听指定的ip ...

  10. 信息安全-加密:RAS 加密

    ylbtech-信息安全-加密:RAS 加密 1.返回顶部 1. RSA 是不对称的加密(加密密钥和解密密钥不同  其中 一个为公钥,一个为私钥): 公钥和私钥的产生是基于一对很大的素数(十进制来说 ...