2012-04-17 8 views
0

非常に複雑なクエリを持つビューがあります(下記参照)。次に、このビューを使用して別の表にデータを挿入します。データベースにはたくさんのデータがあり、挿入クエリを実行すると8時間実行され、最後に実際の挿入が行われます。それは最初にビューからすべての結果を取り出して、それから私のテーブルに挿入するようです。それぞれのレコードを別々に挿入することは可能ですか?ここでビュー内で長時間実行されるT-SQLクエリ

は図である。ここでは

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 
+0

実行するまでに8時間かかりますが、いくつのレコードがフェッチ/挿入されますか? – Thakur

+0

私は実際のデータベースにアクセスできないため、正確なレコード数はわかりませんが、2000年以降のデータがあります。 – andr111

+0

このコードLEFT JOIN PROVIDER p ON p.PROVIDERCODE = ev.PRIMARYPROVIDERCODE WHERE p。 DOCREVNO = 0は、内部結合を左結合に変えます。 http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOINこれはあなたのパフォーマンスの問題ではありませんが、間違ったレコードセットを取得している可能性があります。 – HLGEM

答えて

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

+0

@Cade Rouxが以下の答えで示唆しているように、インデックス作成が適切に行われているかどうかを確認してください。 – Thakur

2

それは無いとはい

個別に各レコードを挿入するために、それは可能です。

各レコードを別々に挿入していますが、最後にコミットするだけです。ダーティーリードを使用すると、非常に長いインサートで、1つの非常に長いインサートで行カウントが増加することがあります。これはACIDのものであり、トランザクション全体をロールバックすることができるため、コミットされるまで他のトランザクションは通常レコードを参照しません。

挿入する行を決定する方法は、実行計画によって異なります。並べ替え(ORDER BY)といくつかの共通のテーブル式があるため、行の決定に時間がかかることがあり、操作の大部分が挿入される行を決定している可能性があります(この操作中に一時記憶域にスプールする可能性があります)そして、それらは非常に急速に挿入されます。

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

また、このようなクエリを実行するには8時間も長すぎると思います。インデックス付けの戦略やテーブルや実行計画の行数については何も言及していないと思いますまずそれらのことを見て、それらについて学ぶ。

PRIMARYPROVIDERCODE、CLIENTNUMBER、STARTINGDATEにインデックスがありますか?また、WHERE句:DOCREVNO = 0およびCMT = 'N'がそのインデックスの先頭にある必要があることにも注意してください。実行計画を見て、何が起きているのかを確認してください。プロダクションにアクセスできない場合でも、プロダクションDBAは実行計画を与えることができます。

0

2番目のCade Rouxは、最適化されたクエリが実行されるよりも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)) 

が、私は時間+クエリを持っていたこのアプローチの分+クエリに変わりはなく、もちろん、すべての状況が異なっている...

+0

提案していただきありがとうございます。私はそれを試し、パフォーマンスを向上させるかどうかを知らせます。 – andr111

1

あなたの問題の一部は、ビューの使用はここでは貧弱なアイデアです。ビュー全体を生成してから、ビュー内のテーブルに参加してフィルタダウンしなければなりません。私がやる最初のことは、その視点を捨てることです。次に、行ごとに実行する必要がある相関サブクエリを削除し、結合で派生テーブルをより効率的に作成します。私はこれを詳細に把握し、あなたが達成しようとしているものを正確に把握する時間はありませんが、何かを達成するために非常に努力しなければならないときは、通常、データベース構造に設計上の問題があります。

関連する問題