26

大量のデータを処理するストアドプロシージャがあります。そのデータを一時テーブルに挿入しています。イベントの全体的な流れは次のようなものです

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主キーを構成します。

更新:私の場合、ソーステーブルの主キーを複製しています。主キーを構成するフィールドは常に一意になることを私は知っています。最後に主キーを追加しても、テーブルの変更が失敗する心配はありません。

しかし、これはさておき、私の質問は、両方が成功すると仮定すると、どちらが速いのかということです。

4

9 に答える 9

17

これは大きく依存します。

ロード後に主キー インデックスをクラスター化すると、クラスター化インデックスは実際にはインデックスではなく、データの論理的な順序であるため、テーブル全体が書き直されます。挿入の実行計画は、計画が決定されたときに配置されているインデックスに依存し、クラスター化されたインデックスが配置されている場合は、挿入の前に並べ替えられます。通常、これは実行計画で確認できます。

主キーを単純な制約にすると、通常の (クラスター化されていない) インデックスになり、オプティマイザーが決定した順序でテーブルにデータが入力され、インデックスが更新されます。

(一時テーブルをロードするこのプロセスの) 全体的な最速のパフォーマンスは、通常、データをヒープとして書き込んでから (非クラスター化) インデックスを適用することだと思います。

ただし、他の人が指摘したように、インデックスの作成は失敗する可能性があります。また、一時テーブルは単独では存在しません。おそらく、次のステップのためにそこからデータを読み取るのに最適なインデックスがあります。このインデックスは、配置または作成する必要があります。 ここで、信頼性 (PK およびその他の制約を最初に適用) と後で速度 (クラスター化インデックスを作成する場合は、少なくともクラスター化インデックスを配置する) のために速度のトレードオフを行う必要があります

于 2009-06-22T22:20:42.163 に答える
8

データベースのリカバリモデルがシンプルまたは一括ログに設定されている場合は、SELECT ... INTO ...UNIONALLが最速のソリューションである可能性があります。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) 

それ以外の場合、CadeRouxは前または後に良いアドバイスをしました。

于 2009-06-23T01:37:13.873 に答える
3

挿入の前に主キーを作成することもできます。主キーがID列にある場合、挿入はとにかく順番に行われ、違いはありません。

于 2009-06-22T21:13:11.270 に答える
2

パフォーマンスの考慮事項よりもさらに重要なことは、テーブルに一意の値が挿入されることを 100% 確信していない場合は、最初に主キーを作成することです。そうしないと、主キーの作成に失敗します。

これにより、重複/不良データを挿入できなくなります。

于 2009-06-22T22:09:10.127 に答える
1

テーブルの作成時に主キーを追加すると、最初の挿入は自由になります (チェックは必要ありません)。2 番目の挿入は、最初の挿入と異なるかどうかを確認するだけです。3 番目の挿入では、2 つの行をチェックする必要があります。一意の制約が設定されているため、チェックはインデックス ルックアップになります。

すべての挿入の後に主キーを追加する場合、すべての行を他のすべての行と照合する必要があります。したがって、主キーを早い段階で追加する方が安価だと思います。

しかし、おそらく Sql Server には、一意性をチェックする非常にスマートな方法があります。ですから、確実に知りたい場合は、測定してください。

于 2009-06-22T21:49:08.950 に答える
1

テーブル全体の挿入ごとに一連のチェックを必要とする非常に「高価な」ストアドプロシージャを改善できるかどうか疑問に思っていたところ、この回答に出くわしました。Sproc では、いくつかの一時テーブルが開かれ、相互に参照されます。主キーを CREATE TABLE ステートメントに追加し (選択で WHERE NOT EXISTS ステートメントを使用してデータを挿入し、一意性を確保していますが)、実行時間が大幅に短縮されました。主キーを使用することを強くお勧めします。必要ないと思うときでも、少なくとも試してみてください。

于 2012-08-11T20:30:33.223 に答える
0

あなたの場合、大きな違いはないと思います:

  • 1回の挿入ごとに、少しずつペナルティを支払うか
  • または、すべての挿入が完了した後に大きなペナルティを支払うことになりますが、1 回だけです。

挿入を開始する前に事前に作成すると、PK 値がシステムで作成されていない場合、データが挿入されているときに PK 違反が発生する可能性があります。

しかし、それ以外は、大きな違いはありません。

マルク

于 2009-06-22T21:18:16.143 に答える
0

これについての私の知識に 100% の自信があるわけではないので、これに答えるつもりはありませんでした。しかし、あまり反応がないように見えるので...

私の理解では、PK は一意のインデックスであり、各レコードを挿入すると、インデックスが更新されて最適化されます。したがって、最初にデータを追加してからインデックスを作成すると、インデックスは一度だけ最適化されます。

したがって、データがクリーンである (PK データが重複していない) と確信している場合は、挿入してから PK を追加します。

ただし、データに重複した PK データが含まれている可能性がある場合は、最初に PK を作成して、できるだけ早く爆発させるようにします。

于 2009-06-22T21:59:10.320 に答える