大量のデータを処理するストアドプロシージャがあります。そのデータを一時テーブルに挿入しています。イベントの全体的な流れは次のようなものです
CREATE #TempTable (
Col1 NUMERIC(18,0) NOT NULL, --This will not be an identity column.
,Col2 INT NOT NULL,
,Col3 BIGINT,
,Col4 VARCHAR(25) NOT NULL,
--Etc...
--
--Create primary key here?
)
INSERT INTO #TempTable
SELECT ...
FROM MyTable
WHERE ...
INSERT INTO #TempTable
SELECT ...
FROM MyTable2
WHERE ...
--
-- ...or create primary key here?
私の質問は、#TempTableテーブルに主キーを作成するのに最適な時期はいつですか?インデックスが必要であるため、すべてのデータを挿入した後に主キー制約/インデックスを作成する必要があると理論付けました主キー情報の作成中に再編成されました。しかし、私は私の下線の仮定が間違っているかもしれないことに気付きました...
関連する場合、使用したデータ型は実際のものです。の中に #TempTable
テーブル、 Col1
およびCol4
が主キーを構成します。
更新:私の場合、ソーステーブルのプライマリキーを複製しています。主キーを構成するフィールドは常に一意であることを知っています。最後に主キーを追加する場合、失敗した変更テーブルについて心配する必要はありません。
ただし、これはともかく、私の両方の質問が成功すると仮定すると、どちらが速いかという質問がまだあります?
PSこれが重複している場合は申し訳ありません。それができるほど基本的ですが、私はそれのようなものを見つけることができませんでした。
これ依存たくさん。
ロード後に主キーインデックスをクラスター化すると、クラスター化インデックスは実際にはインデックスではなく、データの論理的な順序であるため、テーブル全体が書き換えられます。挿入の実行計画は、計画が決定されるときに適切なインデックスに依存し、クラスター化インデックスが適切な場合は、挿入の前にソートされます。通常、これは実行計画に表示されます。
主キーを単純な制約にすると、通常の(クラスター化されていない)インデックスになり、オプティマイザーが決定し、インデックスが更新された順序でテーブルが作成されます。
(一時テーブルを読み込むこのプロセスの)全体で最も速いパフォーマンスは、通常、データをヒープとして書き込み、(非クラスター化)インデックスを適用することだと思います。
ただし、他の人が指摘したように、インデックスの作成は失敗する可能性があります。また、一時テーブルは単独では存在しません。おそらく、次のステップのためにそこからデータを読み取るための最良のインデックスがあります。このインデックスは、配置するか作成する必要があります。 これは、信頼性(最初にPKおよび他の制約を最初に適用)と後で速度(少なくとも1つを使用する場合はクラスター化インデックスを適切に配置するため)で速度のトレードオフを行う必要がある場所です)。
データベースの復旧モデルが単純または一括ログに設定されている場合、SELECT ... INTO ... UNION ALLが最速のソリューションである可能性があります。 SELECT .. INTOは一括操作であり、一括操作は最小限に記録されます。
例えば:
-- first, create the table
SELECT ...
INTO #TempTable
FROM MyTable
WHERE ...
UNION ALL
SELECT ...
FROM MyTable2
WHERE ...
-- now, add a non-clustered primary key:
-- this will *not* recreate the table in the background
-- it will only create a separate index
-- the table will remain stored as a heap
ALTER TABLE #TempTable ADD PRIMARY KEY NONCLUSTERED (NonNullableKeyField)
-- alternatively:
-- this *will* recreate the table in the background
-- and reorder the rows according to the primary key
-- CLUSTERED key Word is optional, primary keys are clustered by default
ALTER TABLE #TempTable ADD PRIMARY KEY CLUSTERED (NonNullableKeyField)
それ以外の場合、Cade Rouxには良いアドバイスがありました:前または後。
挿入の前に主キーを作成することもできます-主キーがID列にある場合、挿入はとにかく順番に行われ、違いはありません。
パフォーマンスに関する考慮事項よりもさらに重要なことは、絶対にそうでない場合は、一意の値がテーブルに挿入されることを100%確信し、最初に主キーを作成することです。そうしないと、主キーの作成に失敗します。
これにより、重複/不良データを挿入できなくなります。
テーブル全体の各挿入で多数のチェックを必要とする非常に「高価な」ストアドプロシージャを改善できるかどうか疑問に思い、この答えに出会いました。 Sprocでは、いくつかの一時テーブルが開かれ、相互に参照します。プライマリキーをCREATE TABLEステートメントに追加しましたが(選択ではWHERE NOT EXISTSステートメントを使用してデータを挿入し、一意性を確保していますが)、実行時間が大幅に削減されました。主キーを使用することを強くお勧めします。必要ないと思う場合でも、少なくとも試してみてください。
テーブルの作成時に主キーを追加すると、最初の挿入は無料になります(チェックは不要です)。2番目の挿入では、最初の挿入と異なるかどうかを確認するだけです。 3番目の挿入では、2行をチェックする必要があります。一意の制約が設定されているため、チェックはインデックスルックアップになります。
すべての挿入の後に主キーを追加する場合、すべての行を他のすべての行と照合する必要があります。したがって、主キーを早期に追加する方が安価だと思います。
ただし、SQL Serverには一意性を確認するための非常にスマートな方法があるかもしれません。確認したい場合は、測定してください!
私はそれがあなたのケースに大きな違いをもたらすとは思わない:
挿入を開始する前に事前に作成すると、could PK値がシステムで作成されていない場合、データの挿入中にPK違反をキャッチする可能性があります。
しかし、それ以外-大きな違いはありません、本当に。
マーク
テーブルの作成時にPKを追加する場合、挿入チェックはO(Tn)
(ここで、Tn
は「n番目の三角形の数」、つまり_1 + 2 + 3 ... + n
_)です。番目の行、以前に挿入された「x-1」行に対してチェックされます
PKを追加するとafterすべての値を挿入します。x番目の行を挿入するとn
のすべての既存の行に対してチェックされるため、チェッカーはO(n^2)
です。
O(Tn)
はO(n^2)
よりも小さいため、最初の方が明らかに高速です。
追伸例:5行を挿入する場合、それは_1 + 2 + 3 + 4 + 5 = 15
_操作対_5^2 = 25
_操作です
私はこれについて自分の知識に100%自信がないので、これに答えるつもりはありませんでした。しかし、あなたは多くの応答を得ているようには見えないので...
私の理解では、PKは一意のインデックスであり、各レコードを挿入すると、インデックスが更新および最適化されます。したがって...最初にデータを追加してからインデックスを作成すると、インデックスは一度だけ最適化されます。
したがって、データがクリーンであると確信している場合(PKデータが重複していない場合)、挿入してからPKを追加します。
ただし、データに重複するPKデータが含まれている可能性がある場合は、最初にPKを作成するので、できるだけ早く爆撃します。