2017-04-20 10 views
3

最初に掲載された質問は、私は事前に虚偽のことをお詫び申し上げます。 テーブルにはチームに割り当てられたレコードが含まれており、最初の割り当ては別のプロセスで行われます。しばしば、エージェントのレコードを再割り当てし、他のチームに均等に分散させる必要があります。私たちは手でこれを一つずつ行ってきましたが、それは面倒でした。だから私はこの解決策を思いついた:SQL Server 2008この更新プログラムループを効率的に行う方法はありますか?

DECLARE @UpdtAgt TABLE (ID INT, Name varchar(25)) 
    INSERT INTO @UpdtAgt 
    VALUES (1, 'Gandalf') 
      ,(2,'Hank') 
      ,(3,'Icarus') 


    CREATE TABLE #UpdtQry (TblID varchar(25)) 
    INSERT INTO #UpdtQry 
    SELECT ShtID 
    FROM TestUpdate 

    DECLARE @RowID INT 
    DECLARE @AgtID INT 
    DECLARE @Agt varchar(25) 
    DECLARE @MaxID INT 
    SET @MaxID = (SELECT COUNT(*) FROM @UpdtAgt) 
    SET @AgtID = 1 

    --WHILE ((SELECT COUNT(*) FROM #UpdtQry) > 0) 
    WHILE EXISTS (SELECT TblID FROM #UpdtQry) 

    BEGIN 
    SET @RowID = (SELECT TOP 1 TblID FROM #UpdtQry) 
    SET @Agt = (SELECT Name FROM @UpdtAgt WHERE ID = @AgtID) 

    UPDATE TestUpdate 
    SET Assignment = @Agt 
    WHERE ShtID = @RowID 

    DELETE #UpdtQry WHERE TblID = @RowID 

    IF @AgtID < @MaxID 
     SET @AgtID = @AgtID + 1 
    ELSE 
     SET @AgtID = 1 


    END 

    DROP TABLE #UpdtQry 

これは本当にこの何かを行うに私の最初の試みです。 100行の更新には約30秒かかります。 UPDATEテーブルのTestUpdateには、CLUSTEREDインデックスのみがあります。これをより効率的にするにはどうすればいいですか?

EDIT:私の説明では、@UpdtAgtと#UpdtQryテーブルをよく定義していませんでした。 @UpdtAgtはレコードを再割り当て中のエージェントを保持し、これが使用されるたびに変更される可能性があります。 #UpdtQryには、どのエージェントレコードを再割り当てするかを定義するWHERE句がありますが、これは使用ごとに変わります。私はこれがもう少し明確になることを願っています。再び、最初に正しいことをしてくれないことに対する謝罪。

EDIT 2:古いWHILE節をコメントアウトし、HABOが提案したものを挿入しました。もう一度ありがとうございます。

+0

どこ 'TestUpdate'テーブル構造のですか? 'CTE'が仕事をすることができるようだ – Sami

+0

1つ以上の行が存在するかどうかを確認するときは、[' EXISTS'](https://msdn.microsoft.com/en-us/library/ms188336)を使う方が効率的です.aspx)でなく、正確に['COUNT'](https://msdn.microsoft.com/en-us/library/ms175997.aspx)を取得し、それがゼロより大きいかどうかをチェックするだけです。原則として、 'ORDER BY'を伴わないで' TOP'を使うことは威嚇されます。 – HABO

+0

HOLY CRAP!それはそれをした! SELECT COUNT(*)の代わりにWHILEでEXISTSを使用すると、30秒から1秒以下になります。どうもありがとうございました! – EFrost

答えて

1

私は、これはあなたが探しているものだと思う:

DECLARE @UpdtAgt TABLE 
(
    ID INT, 
    Name VARCHAR(25) 
) 

INSERT @UpdtAgt 
VALUES (1, 'Gandalf') 
     ,(2, 'Hank') 
     ,(3, 'Icarus') 

UPDATE t 
SET t.Assignment = a.Name 
FROM TestUpdate AS t 
INNER JOIN @UpdtAgt AS a 
    ON t.ShtID = a.ID 

一度にすべての4行を行う必要があること。

P.S ...

あなたが将来的にあなたのオリジナルのポストのようにテーブルを作成した場合は、試してみて、あなたの列とその目的と一致し、変数の命名を保管してください!あなたの例では

あなたは(と私は、彼らがすべて同じものだと思いますか?[私が間違っているなら、私を修正してください!])TblID(最も紛らわしい)IDAgtID、およびShtIDを使用して。変数AgtID@RowIDの変数は@AgtID)を呼び出すと、何が起こっているのかを一目瞭然に見ることができます。同じことがAssignmentNameになります。

+0

あなたの答えをお寄せいただきありがとうございます。私はこれがうまくいくかどうかはわからないが、本番環境のTestUpdateは100kを超えるかなりのサイズのテーブルであり、私はそれを少し更新するしかないだろう。 #UpdtQryテーブルが取り込むものは、更新が必要な部分です。申し訳ありませんが私は私の元の投稿ではっきりしていない場合。プロダクションでは、#UpdtQryテンポラリテーブルの作成にWHERE句があります。 – EFrost

0

これはこのようなもので初めての試みなので、私はあなたの作品をお祝いしたいと思います。それは理想的ではありませんが(とは何ですか?)、それは主な目標を満たします。カーソルと呼ばれるものを使用してこれを行うより良い方法があります。 Microsoftの次のページを使用して、適切な構文を思い出してください。Click here for full instruction on cursors

この記事の最後にあるコードは、自分の状況に対する私の迅速な解決策を示しています。次の点に注意してください。

  1. @TestUpdateテーブルは、永続テーブルを使用せずにクエリがMSSQLで実行されるように定義されています。
  2. @UpdtAgtテーブルのみを一時テーブルとして設定する必要があります。ただし、これを定期的に使用する場合は、永続的なテーブルにするのが最善です。
  3. 最後のCLOSEDEALLOCATEステートメントはです。重要: - これらを忘れるとかなり不快な結果になります。
DECLARE @TestUpdate TABLE (ShtID int, Assignment varchar(25)) 

INSERT INTO @TestUpdate 
    VALUES (1,'Fred') 
    ,(2,'Barney') 
    ,(3,'Fred') 
    ,(4,'Wilma') 
    ,(5,'Betty'),(6,'Leopold'),(7,'Frank'),(8,'Fred') 

DECLARE @UpdtAgt TABLE (ID INT, Name varchar(25)) 

INSERT INTO @UpdtAgt 
VALUES (1, 'Gandalf') 
     ,(2,'Hank') 
     ,(3,'Icarus') 

DECLARE @recid int 
DECLARE @AgtID int SET @AgtID=0 
DECLARE @MaxID int SET @MaxID = (SELECT COUNT(*) FROM @UpdtAgt) 

DECLARE assignment_cursor CURSOR 
FOR SELECT ShtID FROM @TestUpdate 

OPEN assignment_cursor 
FETCH NEXT FROM assignment_cursor 
INTO @recid 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    SET @AgtID = @AgtID + 1 
    IF @AgtID > @MaxID SET @AgtID = 1 

    UPDATE @TestUpdate 
    SET Assignment = (SELECT TOP 1 Name FROM @UpdtAgt WHERE [email protected]) 
    FROM @TestUpdate TU 
    WHERE [email protected] 

    FETCH NEXT FROM assignment_cursor INTO @recid 
END 

CLOSE assignment_cursor 
DEALLOCATE assignment_cursor 

SELECT * FROM @TestUpdate 
+0

私が読んだことの多くは、カーソルの使用を嫌っていますが、私はそれらの経験はほとんどありません。私はカーソルについて誤解しましたか? – EFrost

+0

カーソルを過度に使用したり、複数の人で同じカーソルを同時に実行したり、連続して実行したりすると、カーソルが不正になることがあります。あなたの場合、カーソルは現在のソリューションよりも優れたパフォーマンスを持つ必要があります。 –

関連する問題