1

私はこのように設計されたSQLServerデータベースを持っています:

TableParameter
  Id    (int, PRIMARY KEY, IDENTITY)
  Name1 (string)
  Name2 (string, can be null)
  Name3 (string, can be null)
  Name4 (string, can be null)

TableValue
  Iteration         (int)
  IdTableParameter  (int, FOREIGN KEY)
  Type              (string)
  Value             (decimal)

だから、あなたが今理解したように、TableValueにリンクされていTableParameterます。 TableParameter多次元辞書のようなものです。

TableParameter多くの行(300,000行以上)があるはずです

私のc#クライアントプログラムから、各Compute()関数の後にこのデータベースに入力する必要があります:

for (int iteration = 0; iteration < 5000; iteration++)
{
    Compute();
    FillResultsInDatabase();
}

FillResultsInDatabase()メソッドでは、私はする必要があります:

  1. パラメータのラベルがにすでに存在するかどうかを確認してくださいTableParameter。存在しない場合は、新しいものを挿入する必要があります。
  2. 値を挿入する必要がありますTableValue

ステップ1には時間がかかります!すべてのテーブルTableParameterをIEnumerableプロパティにロードしてから、パラメーターごとに作成します。

.FirstOfDefault( x => x.Name1 == item.Name1 &&
                      x.Name2 == item.Name2 &&
                      x.Name3 == item.Name3 &&
                      x.Name4 == item.Name4 );

それがすでに存在するかどうかを検出するために(そしてIDを取得した後に)。

このようにパフォーマンスが非常に悪いです!

WHEREのすべての行が読み込まれないようにするために、単語で選択しようとしましTableParameterたが、パフォーマンスが低下します。

ステップ1のパフォーマンスを改善するにはどうすればよいですか?

ステップ2の場合、クラシックではパフォーマンスがまだ悪いINSERTです。やってみSqlBulkCopyます。

ステップ2のパフォーマンスを改善するにはどうすればよいですか?

編集済み

ストアドプロシージャを試してみました:

CREATE PROCEDURE GetIdParameter
    @Id     int OUTPUT,
    @Name1  nvarchar(50) = null,
    @Name2  nvarchar(50) = null,
    @Name3  nvarchar(50) = null
AS
SELECT TOP 1 @Id = Id FROM TableParameter
WHERE
TableParameter.Name1 = @Name1   
AND
(@Name2 IS NULL OR TableParameter.Name2= @Name2)
AND
(@Name3 IS NULL OR TableParameter.Name3 = @Name3)
GO

CREATE PROCEDURE CreateValue
    @Iteration int,
    @Type   nvarchar(50),
    @Value  decimal(32, 18),
    @Name1  nvarchar(50) = null,
    @Name2  nvarchar(50) = null,
    @Name3  nvarchar(50) = null
AS
DECLARE @IdParameter int
EXEC GetIdParameter @IdParameter OUTPUT, 
                    @Name1, @Name2, @Name3
IF @IdParameter IS NULL
BEGIN
    INSERT TablePArameter (Name1, Name2, Name3) 
                               VALUES
                              (@Name1, @Name2, @Name3)

    SELECT @IdParameter= SCOPE_IDENTITY()
END
  INSERT TableValue (Iteration, IdParamter, Type, Value) 
                              VALUES
                              (@Iteration, @IdParameter, @Type, @Value)
GO

私はまだ同じパフォーマンスを持っています...:-((受け入れられません)

4

4 に答える 4

2

何が起こっているのかを理解している場合は、ステップ1でデータが存在するかどうかを確認するためにデータベースにクエリを実行しています。存在しない場合はデータを挿入するストアドプロシージャへのdb呼び出しを使用します。したがって、結果を計算してspに渡すだけです。

最初に結果を計算してから、バッチで挿入できますか?

計算関数はデータベースからデータを取得しますか?もしそうなら、あなたはその操作をセットベースの操作に変えて、サーバー自体でそれを実行することができますか?それともその一部でしょうか?

SQLサーバーは大規模なデータセット操作用に設計されていることに注意してください。

編集:コメントの反映 データの挿入ではコードが遅く、挿入を実行する前に挿入を検索し直す必要があるためだと思われるため、検索する列にSQLインデックスを配置する必要があるかもしれません。検索速度を向上させるためにオンにします。

しかし、私には別の考えがあります。

チェックなしでデータを挿入し、後でデータを読み取るときに、そのクエリの重複を削除してみませんか?

于 2010-10-12T10:49:57.733 に答える
0

(私が今のところ知っている)最速の方法はバルクインサートです。ただし、INSERTの行だけではありません。挿入+選択+ユニオンを試してください。それはかなり速く動作します。

insert into myTable
select a1, b1, c1, ...
union select a2, b2, c2, ...
union select a3, b3, c3, ...
于 2010-10-12T13:44:12.527 に答える
0

私はあなたがここで達成しようとしているビジネスプロセスを把握するのに苦労していることを認めなければなりません。

最初のレビューでは、アプリケーション層内でデータ比較を実行しているように見えます。これに反対することをお勧めします。また、データベースエンジンに、データアクセスを管理および実装するために、設計されていることを実行させることをお勧めします。

別の投稿者が述べているように、レコード挿入ロジックを処理するためのストアドプロシージャの作成を検討する必要があることに同意します。この手順では、レコードがすでに存在するかどうかを確認するための簡単なチェックを実行できます。

また、次のことも考慮する必要があります。

  • 4つの名前列に一意性制約を作成して挿入ロジック/ルールを適用します。
  • 4つの名前列を組み込んだカバーする非クラスター化インデックスを作成します。

インサートのパフォーマンスに関しては、おそらく、あなたが見ているものとそれをどのように測定しているかを評価するためのいくつかのメトリックを提供できますか?

基準を与えるために、SQLServerの現在のETL挿入レコードは約1600万行/秒です。どんな数字を期待して見たいですか?

于 2010-10-12T13:30:30.533 に答える
0

name2 --name3がnullになる可能性があるという事実を考えると、パラメータテーブルを再構築することは可能でしょうか。

TableParameter
  Id    (int, PRIMARY KEY, IDENTITY)
  Name  (string)
  Dimension int

これで、インデックスを作成してクエリを簡略化できます。(WHERE name = "TheNameIWant" AND Dimension = "2")

(そして、インデックスについて言えば、パラメータテーブルの名前列にインデックスを付けていますか?)

挿入物のどこでコミットしますか?1つのステートメントをコミットする場合は、複数の挿入を1つにグループ化します。

値を挿入するのがあなただけの場合、速度が本当に重要な場合は、データベースからメモリにすべての値をロードして、そこでチェックします。

いくつかのアイデア

hth

マリオ

于 2010-10-12T11:12:19.330 に答える