如何减少SQL Server中的查询运行时间?

时间:2016-03-18 18:03:59

标签: sql sql-server sql-server-2012

我在下面写了一个查询来从两个不同的表中检索不同的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

查询计划:

enter image description here

可用索引:

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 个答案:

答案 0 :(得分:2)

在没有架构和有限信息的情况下回答,因此无法保证这将解析,但下面是尝试对其进行优化,以便您至少可以理解这些方法。

优化可分为以下几点:

  1. 将复杂查询分成易于理解的单独语句(对于人和优化程序),并且已知优化程序可以很好地理解。例如,很容易优化第一个查询,因为很明显Reg_No以及JOIN子句中使用了WHERE。示例索引可能是:

    CREATE NONCLUSTERED INDEX index_name ON dbo.KeyreferenceDetails(Reg_No)INCLUDE(Pk_Id,KeyreferenceStatus)WHERE KeyreferenceStatus =&#39; L&#39;

  2. ISNULLCOALESCE,{{消除功能(LTRIMRTRIMJOINWHERE等) 1}}。例如,考虑一下:

    PARTITION BY

    优化器将无法在WHERE ISNULL(A.Reg_No, '') <> ''上使用索引,因为您正在为其应用函数。相反,将其重写为:

    Reg_No

  3. 考虑使用WHERE A.Reg_No <> '' AND A.Reg_No IS NOT NULL vs UNION ALL。对于UNION,查询引擎将对两个集进行重复数据删除并仅返回唯一身份。它必须在返回任何数据进行处理之前执行此操作。使用UNION,您可以单独处理两个查询,并将第二个集合附加到第一个集合的末尾。

  4. 您可以使用UNION ALL而不是在IN子句中使用WHERE,并添加一项检查,以查看连接表中的键列是否为NULL确保没有从中返回任何记录,或LEFT OUTER JOIN,这通常会更有效。

  5. 以下是将一些原则应用于您的查询的一种方法示例:

    EXISTS

    由于此处很可能存在语法错误,因此当您查看此内容时,我建议您一次运行每个部分并确保其正常工作,而不是一次执行整个脚本。希望这有帮助!

    此致

    罗斯