0

非常に複雑なクエリを持つビューがあります (以下を参照)。次に、このビューを使用してデータを別のテーブルに挿入します。データベースに大量のデータがあり、挿入クエリを実行すると、8 時間実行され、最後にのみ実際の挿入が行われます。最初にビューからすべての結果を取得してから、それらをテーブルに挿入するようです。各レコードを個別に挿入することはできますか?

ビューは次のとおりです。

CREATE VIEW [dbo].[Enrollment]
AS
WITH CTE AS (SELECT     RN = ROW_NUMBER() OVER (PARTITION BY PRIMARYPROVIDERCODE, CLIENTNUMBER
                               ORDER BY PRIMARYPROVIDERCODE, CLIENTNUMBER, STARTINGDATE), ID, PRIMARYPROVIDERCODE, CLIENTNUMBER, STARTINGDATE, ENDINGDATE
FROM         AUTHORIZE
WHERE     DOCREVNO = 0 AND CMT = 'N'
GROUP BY PRIMARYPROVIDERCODE, CLIENTNUMBER, STARTINGDATE, ENDINGDATE, ID)
    SELECT     [Current Row].ID, [Current Row].RN, [Current Row].PRIMARYPROVIDERCODE, [Current Row].CLIENTNUMBER, [Current Row].STARTINGDATE, 
                            ENDINGDATE =
                                (SELECT     TOP 1 [Next Ending].ENDINGDATE
                                  FROM          CTE[Next Ending]
                                  WHERE      [Next Ending].RN >= [Current Row].RN AND [Next Ending].ENDINGDATE IS NOT NULL AND 
                                                         [Next Ending].PRIMARYPROVIDERCODE = [Current Row].PRIMARYPROVIDERCODE AND 
                                                         [Next Ending].CLIENTNUMBER = [Current Row].CLIENTNUMBER
                                  ORDER BY [Next Ending].RN)
     FROM         CTE[Current Row] INNER JOIN
                            CTE[Previous Row] ON ([Previous Row].PRIMARYPROVIDERCODE = [Current Row].PRIMARYPROVIDERCODE AND 
                            [Previous Row].CLIENTNUMBER = [Current Row].CLIENTNUMBER) AND (([Previous Row].RN = [Current Row].RN AND [Current Row].RN = 1) OR
                            ([Previous Row].RN = [Current Row].RN - 1 AND [Previous Row].ENDINGDATE IS NOT NULL))

INSERT クエリは次のとおりです。

INSERT INTO [dbo].[clientenrollment]
           ([DOCSERNO]
           ,[DOCREVNO]
           ,[USERID]
           ,[SIGNED]
           ,[TIMESTAMP]
           ,[ClientNumber]
           ,[enrollmentdate]
           ,[terminationdate]
           ,[PrimaryProviderCode]
           ,[Action]
           ,[Providername]
           ,[SERVICEMAPCODE])
SELECT REPLACE(STR(6620100322000000 + row_number() over (order by ev.ID asc), 17, 0), ' ', '0')
           ,0
           , NULL
           , 0
           , GETDATE()
           ,ev.CLIENTNUMBER
           ,ev.STARTINGDATE
           ,ev.ENDINGDATE
           ,ev.PRIMARYPROVIDERCODE
           ,auth.ACTION
           ,p.PROVIDERNAME
           ,ms.MapCode  
FROM [dbo].[Enrollment] AS ev
JOIN AUTHORIZE auth ON auth.ID = ev.ID
LEFT JOIN MasterService ms ON ms.Code = auth.SERVICECODE
LEFT JOIN PROVIDER p ON p.PROVIDERCODE = ev.PRIMARYPROVIDERCODE
WHERE p.DOCREVNO = 0
4

4 に答える 4

2

各レコードを個別に挿入することは可能ですか?

はいといいえ。

すでに各レコードを個別に挿入していますが、最後にのみコミットします。ダーティリードを使用する場合、非常に長い挿入で、1つの非常に長い挿入で行数が増加することがあります。他のトランザクションは通常、コミットされるまでレコードを参照しません。これはACIDの問題であり、トランザクション全体がロールバックされる可能性があるためです。

挿入する行をどのように決定するかは、実行プランによって異なります。いくつかの並べ替え(ORDER BY)といくつかの一般的なテーブル式があるため、行の決定には時間がかかる場合があり、操作の大部分が挿入される行の決定である可能性があります(おそらくこの操作中に一時ストレージにスプーリングします) )そしてそれらは非常に迅速に挿入されます。

何らかの方法で操作を分割することにより、個々のトランザクションに単一の行を挿入できる可能性があります。もちろん、操作を停止した場合、操作全体の一部しか完了していない可能性があります。

または、このようなクエリを実行するには8時間は長すぎると思います。インデックス作成戦略や、テーブルの行数や実行プランについて何も言及していない場合は、まずそれらを確認します。物事とそれらについて学びます。

PRIMARYPROVIDERCODE、CLIENTNUMBER、STARTINGDATEのインデックスはありますか?また、WHERE句:DOCREVNO = 0 AND CMT='N'もそのインデックスの最初にある必要がある場合があることに注意してください。実行計画を見て、何が起こっているかを確認します。本番環境にアクセスできない場合でも、本番DBAが実行計画を提供できるはずです。

于 2012-04-17T19:44:08.640 に答える
1

あなたの問題の一部は、ビューの使用がここでは悪い考えです。ビュー全体を生成してから、ビュー内のテーブルに結合してフィルターダウンする必要があります。私が最初にすることは、ビューを捨てることです。次に、相関サブクエリを行ごとに実行する必要があり、結合で派生テーブルからパフォーマンスを向上させるため、相関サブクエリを破棄します。これを詳しく調べて、何を達成しようとしているのかを正確に理解する時間はありませんが、何かを達成するために一生懸命努力しなければならない場合、通常、データベース構造に設計上の問題があることを指摘します.

于 2012-04-17T21:06:04.330 に答える
0

行ごとに挿入したい場合は、SQLでカーソルを使用できます

以下はいくつかの参考資料です

http://www.mssqltips.com/sqlservertip/1599/sql-server-cursor-example/

http://blog.sqlauthority.com/2008/11/20/sql-server-simple-use-of-cursor-to-print-all-stored-procedures-of-database/

http://www.jackdonnell.com/articles/SQL_CURSOR.htm

于 2012-04-17T19:43:49.833 に答える
0

2番目にCadeRouxは、最適化されたクエリが実行されると予想されるよりも8時間長いように思われるので、テーブルのインデックスを確認する必要があると述べます。

また、おそらくJOIN句とサブクエリWHERE/暗黙のJOIN句を単純化する価値があるかもしれないことも付け加えておきます。これを行うには、RANK()関数を使用して類似の行をグループ化し、現在使用している複数の列の代わりにそれらのグループ番号を結合します。

完璧であるとは限りませんが、次のようなものです。

CREATE VIEW [dbo].[Enrollment]
AS
WITH CTE AS (SELECT     GN = RANK() OVER (ORDER BY PRIMARYPROVIDERCODE, CLIENTNUMBER) , RN = ROW_NUMBER() OVER (PARTITION BY PRIMARYPROVIDERCODE, CLIENTNUMBER
                               ORDER BY PRIMARYPROVIDERCODE, CLIENTNUMBER, STARTINGDATE), ID, PRIMARYPROVIDERCODE, CLIENTNUMBER, STARTINGDATE, ENDINGDATE
FROM         AUTHORIZE
WHERE     DOCREVNO = 0 AND CMT = 'N'
GROUP BY PRIMARYPROVIDERCODE, CLIENTNUMBER, STARTINGDATE, ENDINGDATE, ID)
    SELECT     [Current Row].ID, [Current Row].RN, [Current Row].PRIMARYPROVIDERCODE, [Current Row].CLIENTNUMBER, [Current Row].STARTINGDATE, 
                            ENDINGDATE =
                                (SELECT     TOP 1 [Next Ending].ENDINGDATE
                                  FROM          CTE[Next Ending]
                                  WHERE      [Next Ending].RN >= [Current Row].RN AND [Next Ending].ENDINGDATE IS NOT NULL AND 
                                                         [Next Ending].GN = [Current Row].GN
                                  ORDER BY [Next Ending].RN)
     FROM         CTE[Current Row] INNER JOIN
                            CTE[Previous Row] ON ([Previous Row].GN = [Current Row].GN) AND (([Previous Row].RN = [Current Row].RN AND [Current Row].RN = 1) OR
                            ([Previous Row].RN = [Current Row].RN - 1 AND [Previous Row].ENDINGDATE IS NOT NULL))

同様の状況で、このアプローチでは1時間以上のクエリが1分以上のクエリに変わりましたが、もちろんすべての状況が異なります...

于 2012-04-17T19:52:28.403 に答える