集群与非集群
我对SQL(Server 2008)的底层知识有限,现在正在被我们的数据库pipe理员挑战。 让我解释一下(我提到了明显的陈述,希望我是对的,但如果你看错了,请告诉我)情景:
我们有一个表格,为人们提供“法庭命令”。 当我创build表(名称:CourtOrder)时,我创build了这样的表:
CREATE TABLE dbo.CourtOrder ( CourtOrderID INT NOT NULL IDENTITY(1,1), (Primary Key) PersonId INT NOT NULL, + around 20 other fields of different types. )
然后我将一个非聚集索引应用到主键(为了效率)。 我的原因是,它是一个独特的领域(主键),应该索引,主要用于select的目的,因为我们经常Select from table where primary key = ...
然后,我在PersonId上应用了一个CLUSTERED索引。 原因是为了一个特定的人物理上的订单,因为绝大多数工作是获得一个人的订单。 所以, select from mytable where personId = ...
我现在已经被拉上了。 我被告知我们应该把聚集索引放在主键上,并把personId上的正常索引。 这对我来说似乎很奇怪。 首先,为什么要在一个独特的列上放置一个聚集索引? 它是什么聚类? 当然,这是浪费聚集索引? 我相信一个正常的索引将被用在一个独特的列上。 另外,对索引进行聚类将意味着我们不能聚簇一个不同的列(每个表一个,对吧?)。
我被告知我犯了一个错误的理由是他们认为在PersonId上放置一个聚集索引会使插入变慢。 对于select速度提高5%,插入和更新速度将会降低95%。 这是正确和有效的?
他们说,因为我们将personId聚类在一起,所以当我们插入或更改PersonId时,SQL Server必须重新排列数据。
那么我问,为什么SQL有一个CLUSTERED INDEX的概念,如果这么慢呢? 跟他们说的一样慢吗? 我应该如何设置我的索引以达到最佳性能? 我以为SELECT使用的不止是INSERT …但他们说我们在INSERTS上locking问题…
希望可以有人帮帮我。
聚集索引与非聚集索引之间的区别在于聚集索引确定数据库中行的物理顺序 。 换句话说,将聚集索引应用于PersonId
意味着这些行将通过表中的PersonId
进行物理sorting,从而允许在其上进行索引search直接访问该行(而不是非聚集索引,这将引导您该行的位置,添加一个额外的步骤)。
也就是说,主键并不是聚集索引,但并不是前所未有的。 你的情况的问题实际上是你所假设的相反:你想要在聚集索引中的唯一值,而不是重复。 由于聚集索引确定行的物理顺序,如果索引位于非唯一列上,则服务器必须为具有重复键值的行添加背景值(在您的情况下,具有相同行的任何行PersonId
),这样组合的值(键+背景值)是唯一的。
我build议的唯一不是使用代理键(您的CourtOrderId
)列作为主键,而是使用PersonId
的复合主键和一些其他唯一标识列或一组列。 如果这不可能(或不实际),然后把聚集索引放在CourtOrderId
。
我不是一个SQL专家…所以把这个作为开发者的观点,而不是DBA的观点..
在不连续顺序的集群(物理sorting的)索引上插入会导致插入/更新的额外工作。 另外,如果你有许多插入同时发生,并且它们都发生在同一个位置,那么最终会导致争用。 您的具体performance根据您的数据以及您的访问方式而有所不同。 一般的经验法则是根据表中最独特的窄值(通常是PK)构build聚簇索引,
我假设你的PersonId不会改变,所以更新不会在这里发挥作用。 但是考虑PersonId为1 2 3 3 4 5 6 7 8 8的几行快照
现在,为PersonId插入20个新的行。首先,由于这不是一个唯一的键,服务器会在您的值(幕后)中添加一些额外的字节以使其唯一(这也会增加额外的空间),然后将位置这些将居住必须改变。 相比之下插入一个自动递增的PK插入发生在最后。 非技术性的解释可能归结为:如果在表格末尾自然而然地取得更高的价值,那么在插入物品的同时修改现有物品在该位置的位置的话,那么就没有什么“换叶”的工作了。
现在,如果您遇到了插入问题,那么您可能会立即插入一堆相同的(或类似的)PersonId值,导致整个表中不同位置的额外工作,并且碎片正在导致您的死亡。 在你的情况下,切换到PK的缺点是,如果你今天在PersonIds上插入的问题在整个表中的值有所不同,如果你将聚簇索引切换到PK并且所有的插入现在发生在一个那么由于竞争集中度的增加,你的问题可能会变得更糟。 (另一方面,如果你今天的插入不是遍布全部,但都是类似的区域,所以你的问题可能会缓解你的聚集索引从PersonId切换到你的PK,因为你会最小化碎片。)
您的performance问题应根据您的独特情况进行分析,并将这些types的答案仅作为一般准则。 你最好的select就是依靠一个DBA来确认问题所在。 这听起来像你有资源争夺问题,可能超出了简单的索引调整。 这可能是一个更大的问题的症状。 (可能的devise问题,否则资源限制。)
无论如何,祝你好运!
有些作者build议,如果有一个替代scheme可以使范围查询受益,则不要在identity
专栏上“浪费” CI
。
从“MSDN 集群索引devise指南”中 ,应根据以下标准select关键字
- 可以用于经常使用的查询。
- 提供高度的独特性。
- 可以用于范围查询。
您的CourtOrderID
列满足2
。 你的PersonId
满足1
和3
。 由于大多数行最终uniqueifier
添加唯一性,所以您可以将它声明为唯一的,并使用PersonId,CourtOrderID
因为这将是相同的宽度,但更有用,因为聚集索引键被添加到所有NCI作为行定位器这将允许他们涵盖更多的查询。
使用PersonId,CourtOrderID
作为CI的主要问题是逻辑碎片可能会随之而来(这尤其会影响您正在尝试帮助的范围查询),所以您需要监视填充因子和碎片级别并更频繁地执行索引维护。
在以下链接中进行了解释: https : //msdn.microsoft.com/en-us/ms190457.aspx
集群
-
聚簇索引根据其键值对表或视图中的数据行进行sorting和存储 。 这些是包含在索引定义中的列。 每个表只能有一个聚簇索引,因为数据行本身只能按一个顺序sorting。
-
表中的数据行按照sorting顺序存储的唯一时间是表中包含聚集索引的时间。 当一个表具有聚集索引时,该表被称为聚集表。 如果一个表没有聚集索引,它的数据行就被存储在一个叫做堆的无序结构中。
非聚集
-
非聚簇索引具有独立于数据行的结构。 非聚簇索引c 包含非聚簇索引键值,每个键值条目都有一个指向包含键值的数据行的指针 。
-
从非聚集索引中的索引行到数据行的指针称为行定位符。 行定位器的结构取决于数据页是存储在堆还是聚簇表中。 对于堆,行定位器是指向该行的指针。 对于聚簇表,行定位符是聚簇索引键。
-
您可以将nonkey列添加到非聚簇索引的叶级,以绕过现有的索引键限制(900个字节和16个键列),并执行完全覆盖的索引查询。
一些数据库与一些讨厌的select,join一个存储过程 – 只有差异是索引
INDEXES – 集群与非集群
891 rows 10 sec NONCLUSTERED OR 891 rows 14 sec CLUSTERED