当前位置: 首页 > news >正文

聚集索引:三级阶梯SQL Server索引

原文链接:http://www.sqlservercentral.com/articles/Stairway+Series/72351/

 

聚集索引:三级阶梯SQL Server索引

通过大卫·杜兰特,2013/01/25(第一次出版:2011/06/22)

该系列

本文是楼梯系列的一部分:SQL Server的阶梯索引

索引数据库设计的基础,告诉开发人员使用数据库设计者的意图。 不幸的是索引时往往是后加上的性能问题出现。 终于在这里是一个简单的系列文章,应该让任何数据库专业迅速加速

前面的水平在这个楼梯概述了非聚集索引的索引一般和特别。 结论用以下关于SQL Server关键概念索引。 当一个请求到达您的数据库,一个SELECT语句或一个INSERTUPDATEDELETE语句,SQL Server只有三种可能的方法来访问数据表中引用的声明:

  • 访问非聚集索引,避免访问表。 这只可能在索引中包含的所有数据查询这个表所要求的
  • 使用搜索键(s)来访问索引,然后使用所选的书签(s)来访问表的单个行。
  • 忽略了索引和搜索请求的表行。

这个水平首先关注的第三选择上面的列表; 搜索表。 反过来,这将导致我们的讨论集群索引; 一个被提及的话题,但没有涵盖,2级。

AdventureWorks我们将使用的数据库表是在这个水平SalesOrderDetail表。 在121317,足以说明一些好处有聚集索引的表。 有两个外键,它是复杂的足以说明一些设计决策,你必须使你的聚集索引。

示例数据库

尽管我们已经讨论了在一级sample数据库,值得重复。 在整个楼梯,我们将使用示例来说明概念。 这些例子是基于微软的AdventureWorks示例数据库。 我们专注于销售订单。 五表将给我们一个良好的事务性和非事务性数据;客户,销售人员,产品,SalesOrderHeader,SalesOrderDetail。 为了保持专注,我们使用列的一个子集。 因为AdventureWorks规范化,销售人员信息分解成三个表:销售人员,员工和联系。

整个楼梯我们使用以下两个术语,指一行订单互换:“行项目订单细节。 前者是更常见的业务术语; 后者的名字出现在一个AdventureWorks表。

完整的一套表,和它们之间的关系,如图1所示。

 

Zoom in  |  Open in new window

1:表中使用的例子在这个楼梯

注意:
所有TSQL代码所示这楼梯水平随着文章可以下载。

聚集索引

我们先问以下问题:有多少工作需要找到表中的一行(s)如果不使用非聚集索引? 搜索请求的行表意味着扫描一个无序表中每一行吗? 永久或SQL Server序列表的行,以便它可以快速访问他们的搜索键,就像快速访问非聚集索引的搜索键的条目吗? 答案取决于你是否指示SQL Server上创建一个聚集索引表。

与非聚集索引是一个单独的对象,占据自己的空间,聚集索引和表是一样的。 通过创建聚集索引,您指示SQL Server排序表的行索引键序列,在未来保持序列数据的修改。 即将到来的水平会看看生成的内部数据结构来完成这个。 但是现在,想到一个聚集索引排序表。 鉴于连续索引键值,SQL Server可以快速访问这一行; 并且可以通过表的行顺序进行。

出于演示的目的,我们创建两个我们的示例表的副本,SalesOrderDetail; 一个没有索引,一个聚集索引。 关于索引的键列,我们的设计师做出同样的选择AdventureWorks数据库:SalesOrderID/SalesOrderDetailID。 清单1中的代码的副本SalesOrderDetail表。 我们可以随时重新运行这段代码,我们希望从一个白纸开始。

如果存在(选择*sys.tables&# 160;在哪里OBJECT_ID=OBJECT_ID(“dbo.SalesOrderDetail_index”))删除表dbo.SalesOrderDetail_index;如果存在(选择*sys.tables&# 160;在哪里OBJECT_ID=OBJECT_ID(“dbo.SalesOrderDetail_noindex”))删除表dbo.SalesOrderDetail_noindex;选择*dbo.SalesOrderDetail_indexSales.SalesOrderDetail;选择*dbo.SalesOrderDetail_noindexSales.SalesOrderDetail;创建聚集索引IX_SalesOrderDetaildbo.SalesOrderDetail_index(SalesOrderID,SalesOrderDetailID)

清单1:创建SalesOrderDetail表的副本

所以,假设SalesOrderDetail表创建聚集索引前是这样的:

SalesOrderID SalesOrderDetailID ProductID OrderQty UnitPrice
38.10 69389 102201 864 3
34.99 56658 59519 711 1
59044 70000 956 2 1430.442
44.994 48299 22652 853 4
44.994 50218 31427 854 8
34.99 53713 50716 711 1
744.2727 50299 32777 739 1
2024.994 45321 6303 775 6
2.29 72644 115325 873 1
141.615 48306 22705 824 4
120.00 69134 101554 876 1
469.794 48361 23556 760 3
602.346 53605 50098 888 1
183.9382 48317 22901 722 1
8.99 66430 93291 872 1
65281 90265 889 2 602.346
9.99 52248 43812 871 1
47978 20189 794 2 1308.9375

创建上面所示的聚集索引后,生成的表/集群指数看起来像这样:

SalesOrderID SalesOrderDetailID ProductID OrderQty UnitPrice
178.58 43668 106 722 3
20.19 43668 107 708 1
356.90 43668 108 733 3
419.46 43668 109 763 3
714.70 43669 110 747 1
5.70 43670 111 710 1
43670 112 709 2 5.70
43670 113 773 2 2039 .99
43670 114 776 1 2024 .99
43671 115 753 1 2146 .96
43671 116 714 2 28.84
874.79 43671 117 756 1
43671 118 768 2 419.46
43671 119 732 2 356.90
43671 120 763 2 419.46
43671 121 755 2 874.79
43671 122 764 2 419.46
28.84 43671 123 716 1
20.19 43671 124 711 1
20.19 43671 125 708 1
5.70 43672 126 709 6
43672 127 776 2 2024 .99
43672 128 774 1 2039 .99
874.79 43673 129 754 1
28.84 43673 130 715 3
183.94 43673 131 729 1

你看上面所示的示例数据,您可能会注意到,每一个SalesOrderDetailID价值是独一无二的。 不要混淆;SalesOrderDetailID不是表的主键。 的结合SalesOrderID/SalesOrderDetailID是表的主键; 以及聚集索引的索引键。

了解基本的聚集索引

聚集索引键可以由你选择的任何列; 它不需要基于主键。 在我们的例子中,最重要的是,最左侧列的关键是一个外键,SalesOrderID价值。 因此,销售订单的所有行项目中连续出现SalesOrderDetail表。

记住这些额外的点对SQL Server集群索引:

  • 由于聚集索引的条目表的行,没有收藏价值在集群索引条目。 当SQL Server已经在一行,它不需要一个信息,告诉它在哪里找到这一行。
  • 聚集索引总是覆盖查询。 自指数和同一个表,表的每一列的索引。
  • 桌子上有一个聚集索引不影响你选择创建非聚集索引表。

选择聚集索引键列(s)

可以有最多每个表一个聚集索引。 一个表的行可以在只有一个序列。 你需要决定什么序列,如果有的话,最好为每个表; 如果可能的话,创建聚集索引表变得充满了之前的数据。 做这个决定时,请记住,测序不仅意味着订购,这也意味着分组; 在分组由销售订单行项目。

这就是为什么的设计者AdventureWorks数据库的选择SalesOrderDetailIDSalesOrderID的序列SalesOrderDetail; 行项目的自然顺序。
例如,如果一个用户请求一个订单的行项目,他们通常会要求所有订单的行项目。 看一个典型的销售订单的形式告诉我们,订单的打印副本总是包括所有行项目。 它的本质是销售订单业务集群由销售订单行项目。 可能会有偶尔的请求从仓库想看产品而非销售订单行项目; 但大多数的请求; 如来自销售人员或客户,或程序,打印发票,或查询,计算每个订单的总价值; 需要任何销售订单的所有行项目。

用户需求,然而,不确定什么是最好的聚集索引。 本系列以后的水平将覆盖的内部索引; 因为某些内部方面的聚集索引列的索引也会影响你的选择。

如果没有聚集索引表,该表称为堆。 每个表都是一堆或一个聚集索引。 所以,尽管我们经常状态的每个索引分为两种类型,集群或非聚集; 同样重要的是要注意,每个表分成两个类型; 它是一个聚集索引或一堆。 开发人员经常说一个表没有一个聚集索引,但它是更有意义的说表不是一个聚集索引。

只有一种方法为SQL Server来搜索一个堆在寻找行(不含非聚集索引的使用),这是开始在表中的第一行并通过表进行,直到所有的行已经阅读。 没有一个序列,没有搜索键,没有办法快速导航到特定的行。

比较一个聚集索引和一堆

聚集索引的性能评价和一堆,清单1的两个副本SalesOrderDetail表。 一份是堆版,另一方面,我们创建在原始表的聚集索引(SalesOrderID,SalesOrderDetailID)。 表都没有任何非聚集索引。

我们将运行相同的三个查询每个版本的表; 一个检索一行,另一个检索单个订单,所有行和检索单个产品的所有行。 我们现在每个执行的SQL和结果表中所示。

我们的第一个查询检索一行和执行细节如表1所示。

SQL

SELECT *
SalesOrderDetail
SalesOrderID = 43671
SalesOrderDetailID = 120

(1行受影响)
“SalesOrderDetail_noindex”。 扫描数1,逻辑读1495

聚集索引

(1行受影响)
“SalesOrderDetail_noindex”。 扫描数1,逻辑读3

聚集索引的影响

1495年读3IO减少。

评论

没有惊喜。 表扫描121317行找到一个不是非常有效。

1:检索单个行

我们的第二个查询检索所有行一个销售订单,你可以看到表2的执行细节。

SQL

SELECT *
SalesOrderDetail
SalesOrderID = 43671

(11行受影响)
“SalesOrderDetail_noindex”。 扫描数1,逻辑读1495

聚集索引

(11行受影响)
“SalesOrderDetail_noindex”。 扫描数1,逻辑读3

聚集索引的影响

1495年读3IO减少。

评论

与前面的查询相同的统计数据。 堆仍然需要表扫描,而分组的聚集索引11细节行所要求的订单足够近以便检索所需的IO 11行是一样的IO需要检索一行。 即将到来的水平将详细解释为什么没有额外的读取需要检索额外的10行。

2:检索单个SalesOrder所有行

和我们的第三个查询检索一个产品的所有行,执行结果如表3所示。

SQL

SELECT *
SalesOrderDetail
ProductID = 755

(228行受影响)
“SalesOrderDetail_noindex”。 扫描数1,逻辑读1495

聚集索引

(228行受影响)
“SalesOrderDetail_index”。 扫描数1,逻辑读1513

聚集索引的影响

聚集索引版本IO略大; 1513读与1495读。

评论

没有ProductID上非聚集索引列帮助找到一个单一产品的行,两个版本必须扫描。 因为有一个聚集索引的开销,略大表的聚集索引版本; 因此扫描需要几堆比扫描读取。

3:检索单个产品的所有行

我们的第一个两个查询从聚集索引的存在极大地受益; 第三个是大致相等。 是时候有一个聚集索引是损害? 答案是肯定的,它主要是与插入、更新和删除行。 像许多其他方面的索引中遇到这些早期的水平,这也是一个主题,将更详细地介绍一个更高的水平。

一般来说,获取利益大于维护造成损害的; 聚集索引比一堆。 如果你是在一个Azure数据库中创建表,你没有选择的余地; 每个表必须是一个聚集索引。

结论

聚集索引是一个排序表的序列是由您创建索引时,指定由SQL Server和维护。 该表中的任意行快速访问给定键值。 任何一组行,在索引键序列,也很快访问给定的范围键。

每个表只能有一个聚集索引。 的决定应该是聚集索引的列索引键列是最重要的决定,你会让任何表。

在我们的四级我们将把我们的重点从逻辑到物理,介绍页面和区段,并检查指标的物理结构。

转载于:https://www.cnblogs.com/1-1-1-1-2/p/7900450.html

相关文章:

  • es 5 数组reduce方法记忆
  • 用vlan划分实现全网互通,并隔离c1,c3和c2,c4
  • Nginx 目录配置详解
  • 详解最大似然估计(MLE)、最大后验概率估计(MAP),以及贝叶斯公式的理解...
  • linux之理解文件系统上的复制,移动,删除
  • Linux运维 第四阶段 (三) MySQL的SQL语句
  • C# GetSchema Get List of Table 获取数据库中所有的表名以及表中的纪录条数的方法
  • XML技术-Schema约束-Dom4j-Xpath详解
  • 从windows server的文件服务到分布式文件服务(二)
  • linux命令之uptime
  • LLDB调试工具简单使用
  • Linux必会原理之输入网址到看到页面内容原理
  • 通过RMAN备份duplicate异机克隆恢复数据库
  • 用C#设计一个四则运算器
  • j2se学习中的一些零碎知识点8之多线程
  • [PHP内核探索]PHP中的哈希表
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • Apache的80端口被占用以及访问时报错403
  • Javascript 原型链
  • JavaScript对象详解
  • LeetCode29.两数相除 JavaScript
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • PHP 的 SAPI 是个什么东西
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Vue UI框架库开发介绍
  • vue 配置sass、scss全局变量
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 盘点那些不知名却常用的 Git 操作
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 如何优雅地使用 Sublime Text
  • 微服务入门【系列视频课程】
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 为视图添加丝滑的水波纹
  • 一个完整Java Web项目背后的密码
  • Java数据解析之JSON
  • 正则表达式-基础知识Review
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • !$boo在php中什么意思,php前戏
  • #《AI中文版》V3 第 1 章 概述
  • $jQuery 重写Alert样式方法
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (Python) SOAP Web Service (HTTP POST)
  • (SpringBoot)第七章:SpringBoot日志文件
  • (笔试题)分解质因式
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (转载)深入super,看Python如何解决钻石继承难题
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .net Signalr 使用笔记
  • .net web项目 调用webService
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .NET 中各种混淆(Obfuscation)的含义、原理、实际效果和不同级别的差异(使用 SmartAssembly)