zoukankan      html  css  js  c++  java
  • 聚集索引:三级阶梯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和维护。 该表中的任意行快速访问给定键值。 任何一组行,在索引键序列,也很快访问给定的范围键。

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

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

  • 相关阅读:
    一张图片入门Python
    4.1. 如何在Windows环境下开发Python
    你必须知道的EF知识和经验
    XUnit的使用
    如何使用NUnit
    Entity Framework 不支持DefaultValue
    Have You Ever Wondered About the Difference Between NOT NULL and DEFAULT?
    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details
    Entity Framework 与多线程
    sqlite中的自增主键
  • 原文地址:https://www.cnblogs.com/1-1-1-1-2/p/7900450.html
Copyright © 2011-2022 走看看