2012-04-17 26 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 2012-04-17 19:35:31

+0

我不知道確切的記錄數,因爲我沒有訪問實時數據庫,但是有從2000年開始的數據。 – andr111 2012-04-17 19:39:03

+0

此代碼左加入提供者p ON p.PROVIDERCODE = ev.PRIMARYPROVIDERCODE WHERE p。 DOCREVNO = 0將內連接變成左連接。 http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN這不是你的性能問題,但它確實意味着你很可能得到了錯誤的記錄集。 – HLGEM 2012-04-17 20:58:46

回答

0
+0

也正如@Cade Roux在下面的答案中所建議的那樣,檢查您的索引編制是否正確。 – Thakur 2012-04-17 19:50:12

2

是否有可能使其插入每條記錄分別

是,也不是。

這是已經分別插入每個記錄,但它只在最後提交。有時在非常長的插入時,如果使用髒讀取,則可以看到單個非常長的插入時行數增加。沒有其他交易通常會在提交之前看到記錄,因爲這是ACID事件,整個交易可能會回滾。

至於它如何確定要插入的行取決於執行計劃。由於您有一些排序(ORDER BY)和一些常用的表表達式,因此確定行可能需要一段時間,並且當然大部分操作可能會確定要插入的行(可能在此操作期間後臺存儲到臨時存儲器),然後他們很快插​​入。

通過以某種方式打破您的操作,可以在單個事務中插入單行。當然,如果操作停止,您可能只完成整個操作的一部分。

另外,我認爲8小時對於像這樣的查詢運行時間太長,並且由於您沒有提到任何有關索引策略或任何表格或執行計劃中的行數,我會首先看看這些東西並瞭解它們。

您是否有PRIMARYPROVIDERCODE,CLIENTNUMBER,STARTINGDATE的索引?另請注意,WHERE子句:DOCREVNO = 0和CMT ='N'也可能需要在該索引中排在第一位。看看執行計劃,看看發生了什麼。即使您無法訪問生產,生產DBA也應該能夠爲您提供執行計劃。

0

我會第二次說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 2012-04-17 21:00:24

1

你的問題的一部分是使用視圖在這裏是一個不好的主意。您必須生成整個視圖,然後加入視圖中的表格並進行過濾。我會做的第一件事就是拋棄這個觀點。然後我會拋棄相關的子查詢,因爲這些子查詢必須逐行運行,並且您可以更好地執行聯合中的派生表。我沒有時間仔細閱讀這些內容,弄清楚你正在努力完成什麼,但是我會指出,當你必須努力完成某些事情時,你通常會在數據庫結構中遇到設計問題。