web-dev-qa-db-ja.com

このSQL Server制約のPAD_INDEXの目的は何ですか?

テーブルの1つに次の制約が適用されていますが、PAD_INDEXの意味がわかりません。

誰かが私を啓発できますか?

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

SQL Serverのインデックスは B-Tree

  • FILLFACTORは最下層に適用されます
    これは、下図のリーフノード/データレイヤーです

  • PAD_INDEX ONは、「FILLFACTORをすべてのレイヤーに適用する」ことを意味します
    これは、下の図の中間レベルです(ルートとデータの間)

これは、PAD_INDEXがFILLFACTORが設定されている場合にのみ有用であることを意味します。 FILLFACTORは、データページの空き容量を(大体)決定します

MSDNからの写真

B-Tree structure

57
gbn

基本的に、定期的にインデックスに多くのランダムな変更が予想される場合は、PAD_INDEX = ONを設定します。

これにより、インデックスページの分割を回避できます。

インデックスに含まれるランダムレコードの30%以上が定期的に削除されると予想される場合に設定します。

51
SQLador

[〜#〜] msdn [〜#〜] から:

PAD_INDEX = {ON |オフ}

インデックスのパディングを指定します。デフォルトはOFFです。

ON:fillfactorで指定された空き領域の割合が、インデックスの中間レベルのページに適用されます。

OFFまたはfillfactorが指定されていない場合:中間レベルのページはほぼ容量までいっぱいになり、中間ページのキーのセットを考慮して、インデックスが持つことができる最大サイズの少なくとも1行に十分なスペースを残します。

PAD_INDEXオプションは、FILLFACTORが指定されている場合にのみ有用です。これは、PAD_INDEXがFILLFACTORで指定されたパーセンテージを使用するためです。 FILLFACTORに指定されたパーセンテージが1行を許可するほど大きくない場合、データベースエンジンは内部的にパーセンテージをオーバーライドして最小値を許可します。 fillfactorの値がどれだけ低いかに関係なく、中間インデックスページの行数は2未満にはなりません。

下位互換性のある構文では、WITH PAD_INDEXはWITH PAD_INDEX = ONと同等です。

20
Edwin de Koning

これは実際には非常に複雑な主題です。 PAD_INDEXを有効にすると劇的な効果が得られます読み取りパフォーマンスと大きなテーブルのメモリ負荷に影響します。テーブルが大きいほど、効果は大きくなります。原則として、いくつかの非一般的カテゴリに分類されない限り、このままにしておきたいと思います。次に、このアドバイスに注意深く従ってください。以下の例で示すように、PAD_INDEXがONのときにFILLFACTORを調整すると、指数関数効果が生じる可能性があるため、慎重にバランスを取る必要があります。

  1. PAD_INDEX ALWAYSは常に読み取りに悪影響を及ぼします! FILLFACTORを低くするほど効果が大きくなるため、FILLFACTORをオンにするときは、FILLFACTORの値に注意を払う必要があります。大きなテーブルでは、本質的にリーフスプリットの削減という観点からFILLFACTORについて考えるのをやめ、中間の膨張と中間のスプリットに対する影響について考え始める
  2. PAD_INDEXが100,000行未満のインデックスに有用な影響を与えることはほとんどありません。また、挿入が常にテーブルの最後にある場合、IDまたは挿入時型のカラムをカバーするインデックスには決してプラスの効果はありません。
  3. 上記から、PAD_INDEXをオンにする場合は、マイナスの効果とプラスの効果のバランスを慎重にとる必要があることがわかります。

経験則:PAD_INDEXは、非常に幅の広い非クラスター化インデックス、非常に狭いテーブルのクラスター化インデックス、または挿入が高度にクラスター化されていない限り10万行未満のテーブルではほとんど役に立ちません疑わしい場合があります。

その仕組みを理解する必要があります:インデックスに挿入する場合、行は適切な範囲のキーを含むリーフブロックに収まる必要があります。通常、クラスター化インデックスには非クラスター化インデックスよりもはるかに広い行があるため、リーフブロックが保持する行の数は少なくなります。 FillFactorは、リーフに新しい行のためのスペースを作成しますが、非常に幅の広い行または均等に分散されるのではなくクラスター化された大量の挿入の場合、分割を防ぐために十分なスラック(1ピクセルの塗りつぶし)を作成することはしばしば非現実的または不可能です。

分割が発生すると、新しいブロックを指す新しい中間行が作成され、その行は適切なブロックに収まる必要があります。その中間ブロックがいっぱいの場合、最初に分割する必要があります。特に不運な場合、スプリットはルートまでずっと実行できます。ルートが分割されると、新しいインデックスレベルが作成されます。

PAD_INDEXのポイントは、中間レベルのブロックに最小限の空き領域を強制することです。

再構築後、下位レベルにスペースがほとんどないか、まったくない場合があります。そのため、多くのリーフ分割があり、PAD_INDEXがオンになっていない場合は、あらゆる場所で中間体を大量に分割できます。

ただし、ほとんどの場合、FILLFACTORを使用してスプリットを管理できます。挿入パターンで大きな分割の問題が発生すると、十分な空き領域がないことを事実上保証し、PAD_INDEXをオンにすると、より深いレベルの領域を提供することでこれを軽減できます。

例の場合

10万行の顧客テーブルがあります。任意の日に、顧客の約5%がアクティブになります。顧客ごとのアクティビティを時間ごとに記録するテーブルがあります。顧客は平均20のアクションを実行し、説明には平均で1Kかかります。したがって、100MBのデータを収集し、すでにテーブルに1年あると仮定します。36GBです。

テーブルには、キー列のcustomer_numberおよびinsert_time(この順序で)を持つ1Kb行の挿入があります。明らかに、平均的な顧客は、予想される20行を挿入しながら8Kリーフブロックを数回分割します。これは、各行が分割および分割および分割されるまで、同じブロックの前の行の直後に挿入されるためです(クラスター化されていないヒープのみを考慮しますインデックス...)。適切なリーフを指している中間ブロックに、少なくとも4行(実際にはおそらく8ですが...)に十分なスペースがない場合、中間ブロックを分割する必要があります。この例のキーは22バイトを占めるため、中間ブロックには367エントリを保持できます。つまり、4つのエントリを保持するには、中間ブロックに6%の空き領域、または94%の空き領域が必要です。

ブロックは8行しか保持できないため、1%FILLFACTORでさえリーフブロックの分割を停止しないことに注意してください。 FILLFACTORを80%に設定すると、リーフが分割される前に1行しか追加できませんが、PAD_INDEXがオンの場合、中間ブロックごとに800バイトを超える空き領域が挿入されます。 88だけが必要な場合、それはすべての中間ブロックに対して〜800空バイトです。

これは本当に重要です!:テーブルにすでに36M行がある場合、80%を使用すると、中間ブロックごとに294行、つまり122Kブロックを意味し、98MBを中間ブロック構造に注入します。 94%では、ブロックごとに345行が収まるので、中間ブロックは104Kのみです(はい、簡単にするために下位レベルを省略しています)。 104Kブロックのそれぞれに88バイトを追加しても、98MBではなく9.2MBしか追加されません。

ここで、私の顧客の5%だけが何かをしたと考えてください。 20を超えるものとそうでないものがあったため、一部のブロックはとにかく分割され、その日のインデックス行(100k/8 * 22)を保持するのに実際に必要なのは275KBだけだったので、9.2MBの8.9MBだけがデッドエアだった。分割防止が重要な場合、9MBの価値がありますが、私は98MBについてもっと考えています。

つまり、PAD_INDEXをオンにすると、リーフの分割を完全に制御することをgivingめ、中間の分割を制御することになります。

最初の中間レベル以外は気にしないでください!クラスタリング(この場合は、customer_numberのクラスタリング)によって引き起こされるバタフライ効果があり、ウィンドウで計算が行われます。挿入が完全に均一でない限り、膨張とスプリットのバランスを取るための適切な数を見つける際のエラーのマージンは、通常、低レベルのブロックスペースの効果よりもはるかに大きくなります。

7
bielawski

@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%を達成できました。その前提でこの設定を使用すると危険ですか?

0
Peter_K