我写了下面的查询来从两个不同的表中检索不同的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表:
Index Name ---------------+ Column Name ----------------- + Index Type
IX_KeyreferenceDetails_I | Reg_No | NONCLUSTERED
IX_KeyreferenceDetails_II | KeyreferenceStatus | NONCLUSTERED
库存表:
Index Name ---------------+ Column Name ----------------- + Index Type
IX_Inventory_I | Inv_H_Reg_No | NONCLUSTERED
MobileMessageDetails表:
Index Name --------------- + Column Name ----------------- + Index Type
IX_MobileMessageDetails_I | Txt_RegNo | NONCLUSTERED
IX_MobileMessageDetails_II | Txt_INOUT | NONCLUSTERED
放置表:
Index Name ---------------+ Column Name ----------------- + Index Type
IX_Place_I | Place_Shrt_Code | NONCLUSTERED
IX_Place_I | Status | NONCLUSTERED
我在上面的查询中为所有使用的表创建了必需的索引.但查询成本很高.如何减少SQL Server中的查询运行时间?
统计输出:
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.
更新:
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
)
最佳答案 回答没有架构和有限的信息,因此不保证这将解析,但下面是尝试优化它,以便您至少可以理解这些方法.
优化可以分为几点:
>将复杂查询分离为更易于理解的单独语句(对于人和优化程序),并且已知优化程序可以很好地使用.例如,很容易优化第一个查询,因为很明显Reg_No用在JOIN和WHERE子句中.示例索引可能是:
CREATE NONCLUSTERED INDEX index_name ON dbo.KeyreferenceDetails(Reg_No)INCLUDE(Pk_Id,KeyreferenceStatus)WHERE KeyreferenceStatus =’L’
>消除JOIN,WHERE,PARTITION BY中的函数(ISNULL,COALESCE,LTRIM,RTRIM等).例如,考虑一下:
在哪里ISNULL(A.Reg_No,”)<> “”
优化器将无法在Reg_No上使用索引,因为您正在向其应用函数.相反,将其重写为:
在哪里A.Reg_No<> ”和A.Reg_No不是NULL
>考虑使用UNION ALL vs UNION.对于UNION,查询引擎将对两个集进行重复数据删除,并仅返回唯一身份验证.它必须在返回任何数据进行处理之前执行此操作.使用UNION ALL,您可以单独处理两个查询并将第二个集合附加到第一个集合的末尾.
>不是在WHERE子句中使用IN,而是可以使用LEFT OUTER JOIN并添加一个检查,以查看连接表中的键列是否为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
由于此时很可能存在语法错误,因此当您查看此错误时,我建议您一次运行每个部分并确保其正常工作,而不是一次执行整个脚本.希望这可以帮助!
问候,
罗斯