簡體   English   中英

如何減少SQL Server中的查詢運行時間?

[英]How to reduce query running time in SQL server?

我寫了下面的查詢來從兩個不同的表中檢索不同的RegNo。 但是在查詢下面需要將近25秒來檢索結果。 在庫存表中,有超過150萬條記錄。

Select F.PKID, F.RegNo
From
(
  Select E.PKID, E.RegNo 
  Row_Number() Over(Order By E.RegNo Asc) RowNo
  From
  (
    Select C.PKID, C.RegNo
    From
    (
      Select Pk_Id PKID, LTrim(RTrim(A.Reg_No)) RegNo, 
      Row_Number() Over(Partition By LTrim(RTrim(A.Reg_No)) 
      Order By (Select Null)) RegRowNo
      From dbo.KeyreferenceDetails A (NoLock)
      Where A.KeyreferenceStatus = 'L' 
      And A.Reg_No Like @Value And IsNull(Reg_No, '') <> '' And Not Exists
      (
        Select 1 From dbo.INVENTORY B (NoLock) 
        Where A.Reg_No = B.Inv_H_Reg_No
      ) 
    ) C
    Where C.RegRowNo = 1 And IsNull(C.RegNo, '') <> '-'
    Union
    Select D.PKID, D.RegNo
    From 
    (
      Select Pk_ID PKID, LTrim(LTrim(Txt_RegNo)) RegNo, 
      Row_Number() Over(Partition By LTrim(LTrim(A.Txt_RegNo)) 
      Order By (Select Null)) RegRowNo
      From dbo.MobileMessageDetails A (Nolock)  
      Left Join dbo.PLACE P (Nolock) On P.Place_Shrt_Code  = A.Txt_YarddCode 
      And P.[Status] = 'L'
      Left Join dbo.INVENTORY B (Nolock) On A.Txt_RegNo = B.Inv_H_Reg_No            
      Where A.Txt_INOUT In('IN', 'MOBILE') And IsNull(A.Txt_RegNo, '') <> '' And B.Inv_H_Pk_Id Is Null 
      And A.[Status] = 'L' And Txt_RegNo Like @Value 
    ) D
    Where D.RegRowNo = 1 And IsNull(D.RegNo, '') <> '-'
 ) E
) F
Where F.RowNo > 0 And F.RowNo <= 20

查詢計划:

在此輸入圖像描述

可用指數:

KeyreferenceDetails table:

 Index Name ---------------+ Column Name ----------------- + Index Type
 IX_KeyreferenceDetails_I  |  Reg_No                       | NONCLUSTERED   
 IX_KeyreferenceDetails_II |  KeyreferenceStatus           | NONCLUSTERED

Inventory table:

 Index Name ---------------+ Column Name ----------------- + Index Type
 IX_Inventory_I            | Inv_H_Reg_No                  | NONCLUSTERED   

MobileMessageDetails table:

 Index Name --------------- + Column Name ----------------- + Index Type
 IX_MobileMessageDetails_I  | Txt_RegNo                     | NONCLUSTERED
 IX_MobileMessageDetails_II | Txt_INOUT                     | NONCLUSTERED

Place table:

 Index Name ---------------+ Column Name ----------------- + Index Type
 IX_Place_I                | Place_Shrt_Code               | NONCLUSTERED  
 IX_Place_I                | Status                        | NONCLUSTERED

我在上面的查詢中為所有使用的表創建了必需的索引。 但查詢成本很高。 如何減少SQL Server中的查詢運行時間?

Statistics Output:

SQL Server Execution Times:
CPU time = 0 ms,  elapsed time = 0 ms.
Table 'INVENTORY'. Scan count 6, logical reads 382, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'KeyreferenceDetails'. Scan count 15, logical reads 9062, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Mobile_MessageDetails'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#TempItemsCount_____________________________________________________________________________________________________0000000118A9'. Scan count 0, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 20733 ms,  elapsed time = 7844 ms.
Table 'INVENTORY'. Scan count 6, logical reads 382, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'KeyreferenceDetails'. Scan count 14, logical reads 9062, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Mobile_MessageDetails'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#VehicleRegDetails__________________________________________________________________________________________________0000000118AB'. Scan count 0, logical reads 20, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 21139 ms,  elapsed time = 8146 ms.
Table '#TABLE_SCHEMA_______________________________________________________________________________________________________0000000118AA'. Scan count 0, logical reads 1, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Update:

Insert Into #TempItemsCount(TotalCount)
Select Count(E.PKID)
From
 (
   Select E.PKID, E.RegNo 
      Row_Number() Over(Order By E.RegNo Asc) RowNo
      From
      (
        Select C.PKID, C.RegNo
        From
        (
          Select Pk_Id PKID, LTrim(RTrim(A.Reg_No)) RegNo, 
          Row_Number() Over(Partition By LTrim(RTrim(A.Reg_No)) 
          Order By (Select Null)) RegRowNo
          From dbo.KeyreferenceDetails A (NoLock)
          Where A.KeyreferenceStatus = 'L' 
          And A.Reg_No Like @Value And IsNull(Reg_No, '') <> '' And Not Exists
          (
            Select 1 From dbo.INVENTORY B (NoLock) 
            Where A.Reg_No = B.Inv_H_Reg_No
          ) 
        ) C
        Where C.RegRowNo = 1 And IsNull(C.RegNo, '') <> '-'
        Union
        Select D.PKID, D.RegNo
        From 
        (
          Select Pk_ID PKID, LTrim(LTrim(Txt_RegNo)) RegNo, 
          Row_Number() Over(Partition By LTrim(LTrim(A.Txt_RegNo)) 
          Order By (Select Null)) RegRowNo
          From dbo.MobileMessageDetails A (Nolock)  
          Left Join dbo.PLACE P (Nolock) On P.Place_Shrt_Code  = A.Txt_YarddCode 
          And P.[Status] = 'L'
          Left Join dbo.INVENTORY B (Nolock) On A.Txt_RegNo = B.Inv_H_Reg_No            
          Where A.Txt_INOUT In('IN', 'MOBILE') And IsNull(A.Txt_RegNo, '') <> '' And B.Inv_H_Pk_Id Is Null 
          And A.[Status] = 'L' And Txt_RegNo Like @Value 
        ) D
        Where D.RegRowNo = 1 And IsNull(D.RegNo, '') <> '-'
    ) E
 )

回答沒有架構和有限的信息,因此不保證這將解析,但下面是嘗試優化它,以便您至少可以理解這些方法。

優化可以分為幾點:

  1. 將復雜查詢分成易於理解的單獨語句(對於人和優化器),並且已知優化器可以很好地使用。 例如,很容易優化第一個查詢,因為很明顯Reg_No用在JOINWHERE子句中。 示例索引可能是:

    CREATE NONCLUSTERED INDEX index_name ON dbo.KeyreferenceDetails(Reg_No)INCLUDE(Pk_Id,KeyreferenceStatus)WHERE KeyreferenceStatus ='L'

  2. 消除JOINWHEREPARTITION BY函數( ISNULLCOALESCELTRIMRTRIM等)。 例如,考慮一下:

    WHERE ISNULL(A.Reg_No, '') <> ''

    優化器將無法在Reg_No上使用索引,因為您正在向其應用函數。 相反,將其重寫為:

    WHERE A.Reg_No <> '' AND A.Reg_No IS NOT NULL

  3. 考慮使用UNION ALLUNION 對於UNION ,查詢引擎將對兩個集進行重復數據刪除,並僅返回唯一身份驗證。 它必須在返回任何數據進行處理之前執行此操作。 使用UNION ALL您可以單獨處理兩個查詢並將第二個集合附加到第一個集合的末尾。

  4. 您可以使用LEFT OUTER JOIN而不是在WHERE子句中使用IN ,並添加一個檢查以查看連接表中的鍵列是否為NULL以確保沒有從它返回記錄,或者是EXISTS ,這通常是更有效地執行。

下面是將一些原則應用於查詢的一種方法示例:

IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp;
GO
SELECT  PKID = Pk_Id, 
        RegNo = LTrim(RTrim(A.Reg_No)), 
        RegRowNo = Row_Number() Over(Partition By LTrim(RTrim(A.Reg_No)) Order By (Select Null))
INTO    #temp
FROM    dbo.KeyreferenceDetails A WITH(NOLOCK)
        LEFT OUTER JOIN dbo.INVENTORY B WITH(NOLOCK) ON A.Reg_No = B.Inv_H_Reg_No
WHERE   B.Inv_H_Reg_No IS NULL
AND     A.KeyreferenceStatus = 'L' 
And     A.Reg_No Like @Value 
And     A.Reg_No IS NOT NULL
AND     A.Reg_No <> '';

INSERT INTO #temp (PKID, RegNo, RegRowNo)
  SELECT  PKID = Pk_ID, 
          RegNo = LTrim(LTrim(A.Txt_RegNo)), 
          RegRowNo = Row_Number() Over(Partition By LTrim(LTrim(A.Txt_RegNo)) Order By (Select Null)) 
  FROM    dbo.MobileMessageDetails A WITH(NOLOCK)
          LEFT OUTER JOIN dbo.PLACE P WITH(NOLOCK) ON P.Place_Shrt_Code  = A.Txt_YarddCode AND P.[Status] = 'L'
          LEFT OUTER JOIN dbo.INVENTORY B WITH(NOLOCK) ON A.Txt_RegNo = B.Inv_H_Reg_No            
  WHERE   B.Inv_H_Pk_Id Is Null 
  AND     A.Status = 'L' 
  AND     A.Txt_RegNo Like @Value 
  And     A.Txt_RegNo IS NOT NULL
  AND     A.Txt_RegNo <> ''
  AND     A.Txt_INOUT In ('IN', 'MOBILE');

IF OBJECT_ID('tempdb..#final') IS NOT NULL DROP TABLE #final;
GO
SELECT  t.PKID, 
        t.RegNo,
        RowNo = Row_Number() Over(Order By t.RegNo Asc)
INTO    #final
FROM    #temp t;
WHERE   t.RegNo <> '-'

SELECT  F.PKID, F.RegNo
FROM    #final F
WHERE   F.RowNo BETWEEN 1 AND 20

GO
DROP TABLE #temp, #final

由於此時很可能存在語法錯誤,因此當您查看此錯誤時,我建議您一次運行每個部分並確保其正常工作,而不是一次執行整個腳本。 希望這可以幫助!

問候,

羅斯

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM