PAD_INDEX在此SQL Server约束中的用途是什么?

时间:2011-07-28 09:47:17

标签: sql sql-server indexing

我将以下约束应用于我的某个表,但我不知道PAD_INDEX的含义。

有人可以启发我吗?

CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED 
(
    [EmployeeId] ASC
) WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
        ^--------------^
         this part here

5 个答案:

答案 0 :(得分:56)

SQL Server中的索引是B-Tree

  • FILLFACTOR适用于底层
    这是下图中的叶节点/数据层

  • PAD_INDEX ON表示“将FILLFACTOR应用于所有图层”
    这是下图中的中间级别(根和数据之间)

这意味着PAD_INDEX仅在设置了FILLFACTOR时才有用。 FILLFACTOR确定数据页面中的可用空间(大致)

A picture from MSDN

B-Tree structure

答案 1 :(得分:50)

基本上,如果您期望定期对索引进行大量随机更改,则将PAD_INDEX设置为ON。

这有助于避免索引页面拆分。

当我希望定期删除索引中包含的30%以上的随机记录时,我会将其设置为开启状态。

答案 2 :(得分:20)

来自MSDN

PAD_INDEX = {ON |关闭}

指定索引填充。默认为OFF。

ON: fillfactor指定的可用空间百分比将应用于索引的中间级页面。

未指定OFF或fillfactor: 考虑到中间页面上的一组键,中间级页面被填充到接近容量,为索引可以具有的最大大小的至少一行留下足够的空间。

PAD_INDEX选项仅在指定FILLFACTOR时有用,因为PAD_INDEX使用FILLFACTOR指定的百分比。如果为FILLFACTOR指定的百分比不足以允许一行,则数据库引擎会在内部覆盖允许最小值的百分比。无论fillfactor的值有多低,中间索引页上的行数都不会少于2。

在向后兼容语法中,WITH PAD_INDEX等效于WITH PAD_INDEX = ON。

答案 3 :(得分:5)

这实际上是一个非常复杂的主题。 打开PAD_INDEX可能会对大型表的读取性能和内存压力产生巨大影响。桌子越大,效果越好。通常,除非您不属于某些“不常见”类别,否则我想将其保留。然后,认真遵循此建议。如以下示例所示,在PAD_INDEX设置为ON时调整FILLFACTOR可能会产生指数效应,需要仔细平衡。

  1. PAD_INDEX总是对读取有不利影响! FILLFACTOR的值越低,效果越大,因此打开它时需要密切注意FILLFACTOR的值。在大型表上,您基本上停止就减少叶片分裂而考虑FILLFACTOR,而开始考虑其对中间膨胀与中间分裂的影响
  2. PAD_INDEX很少会对少于100,000行的索引产生有用的影响,而对于覆盖标识或插入时间类型的列(因为插入始终位于表的末尾),NEVER永远不会产生积极的影响。
  3. 从上面您应该看到,如果打开PAD_INDEX,则必须仔细权衡负面影响和正面影响。

经验法则:PAD_INDEX很少在非聚集索引上使用,除非它们非常宽,在非常狭窄的表的聚集索引上,或者在行数少于10万的表上,除非插入量很大聚集在一起,甚至可能会令人怀疑。

您必须了解其工作原理: 当您插入索引时,该行必须适合包含适当范围的键的叶块。聚簇索引通常比非聚簇索引具有更宽的行,因此它们的叶块容纳的行更少。 FillFactor为叶中的新行创造了空间,但是如果行很宽或大量插入物聚集在一起而不是均匀分布,那么创建足够的松弛度(1-pct填充)以防止分裂通常是不切实际或不可能的。

发生拆分时,将创建一个新的中间行以指向新块,并且该行必须适合其相应的块。如果该中间块已满,则必须先将其拆分。如果您特别不幸,拆分可能会一直进行到根。当根分裂时,您最终会创建一个新的索引级别。

PAD_INDEX的目的是在中间级别的块中强制使用最小的可用空间。

重建后,较低级别的空间可能很小或没有。因此,如果您有很多叶片分裂而PAD_INDEX没有打开,那么您可以在整个地方大规模分裂中间体!

尽管大多数情况下,拆分都可以使用FILLFACTOR进行管理。更大的拆分问题发生在插入模式上,实际上可以确保您没有足够的可用空间,然后打开PAD_INDEX可以通过提供更深的级别的空间来缓解这种情况,因此当拆分发生时,您不太可能发生大量的多级拆分。

案例

我有一个包含10万行的客户表。在任何一天,大约有5%的客户会活跃。我有一个表,按时间记录客户的活动。客户平均执行20项操作,而描述平均需要1K。因此,我收集了100MB的数据,并假设我已经在表中已经有一年了-所以是36GB。

该表具有1Kb行的插入,其中有key_customer_number和insert_time(按此顺序)。显然,普通客户会在插入其预期的20行的同时拆分8K叶子块,因为每一行将立即在同一块中的前一行之后插入,直到拆分,拆分和拆分为止(使一个对象仅考虑非群集的堆)索引...)。如果指向适当叶子的中间块没有足够的空间容纳至少4行(实际上可能是8行,但是...),则中间块将需要拆分。给定此示例的密钥占用22个字节,一个中间块可以容纳367个条目。这意味着我在中间块中需要6%的可用空间或94%的填充量来容纳4个条目。

请注意,即使1%的填充因子也不会停止叶子块拆分,因为一个块只能容纳8行。将FILLFACTOR设置为80%将仅允许在叶子拆分之前添加1行,但是如果启用PAD_INDEX,则将为每个中间块注入800字节以上的可用空间。当我只需要88时,每个中间块都只有800个空字节。

这真的很重要!:因此,如果表中已经有3,600万行,则使用80%表示每个中间块294行,即122K块,这意味着我已将98MB注入中间94%的块结构允许每个块容纳345行,因此只有104K中间块(是的,为简单起见,我省略了较低的级别)。向104K块中的每个块添加88字节仅增加了9.2MB而不是98MB。

现在考虑只有5%的客户做了任何事情。有些执行超过20项操作,有些执行较少的操作,因此无论如何都要拆分一些块,并且由于实际上只需要275KB来保存当天的索引行(100k / 8 * 22),所以最好的情况是,我的9.2MB中只有8.9MB死了。如果拆分预防很重要,那么它值得9mb,但是我会更努力地考虑98mb。

因此,通过打开PAD_INDEX,我应该完全放弃控制叶拆分,而转向控制中间拆分。

除了第一个中级水平,别担心什么!任何聚类(在本例中为customer_number的聚类)都会引起蝶形效应,这将使您在窗口外进行的任何计算都无效。除非您的插入片段完全均匀,否则找到正确的数字以平衡膨胀和分割的错误余量通常会比较低级别的块空间的影响大。

答案 4 :(得分:0)

@bielawski 您仅描述了PAD_INDEX = ON并且FILLFACTOR在1到99之间的情况。 在我插入有序行(总是比上一个更新的行)的情况下,您在考虑将PAD_INDEX = ON和FILLFACTOR = 0或100设置为什么。

CREATE CLUSTERED INDEX [IX_z_arch_export_dzienny_pre] ON [dbo].[z_arch_export_daily_pre]
(
    [Date] ASC,
    [Object Code] ASC,
    [From date] ASC,
    [Person_role] ASC,
    [Departure] ASC,
    [Room code] ASC,
    [period_7_14] ASC
)WITH (PAD_INDEX = ON, FILLFACTOR=100)


insert into z_arch_export_daily_pre
select * from export_daily_pre
order by [Date] ASC,[Object Code] ASC,[From date] ASC,[Person_role] ASC,[Departure] ASC,[Room code] ASC,[period_7_14] ASC

我100%保证所有新行都将在索引的“末尾”插入,只有使用此选项(PAD_INDEX = ON,FILLFACTOR = 100),插入后我才能获得0.01%的碎片索引。 在这种假设下使用此设置会有些危险吗?