我在SQL Server 2016中编写此查询:
\
此代码需要26秒:
"
但: 我对该代码进行了另一种状态的测试,但在3秒内返回了22,000条记录
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[s2_GetReceivedDocumentsCount]
@_Username NVARCHAR(MAX),
@_SearchText NVARCHAR(MAX),
@_States NVARCHAR(MAX),
@_Senders NVARCHAR(MAX),
@_Date1 NVARCHAR(MAX),
@_Date2 NVARCHAR(MAX),
@_Filter1ID NVARCHAR(MAX),
@_Filter1Value NVARCHAR(MAX)
AS
BEGIN
--https://blogs.technet.microsoft.com/mdegre/2011/11/06/what-is-parameter-sniffing/
DECLARE @Username NVARCHAR(MAX)
DECLARE @Fild BIT
DECLARE @SearchText NVARCHAR(MAX)
DECLARE @States NVARCHAR(MAX)
DECLARE @Senders NVARCHAR(MAX)
DECLARE @Date1 NVARCHAR(MAX)
DECLARE @Date2 NVARCHAR(MAX)
DECLARE @Filter1ID NVARCHAR(MAX)
DECLARE @Filter1Value NVARCHAR(MAX)
SELECT
@Username = @_Username,
@SearchText = @_SearchText,
@States = @_States,
@Senders = @_Senders,
@Date1 = @_Date1,
@Date2 = @_Date2,
@Filter1ID = @_Filter1ID,
@Filter1Value = @_Filter1Value
SELECT @SearchText = LTRIM(RTRIM(IsNull(@SearchText, '')))
SELECT @Filter1ID = LTRIM(RTRIM(IsNull(@Filter1ID, '')))
SELECT @Filter1Value = LTRIM(RTRIM(IsNull(@Filter1Value, '')))
DECLARE @PersonalPostID INT = NULL
SELECT @PersonalPostID = p.PostID
FROM Person pr
JOIN PersonPost pp ON pp.PersonID = pr.PersonID
JOIN Post p ON p.PostID = pp.PostID
WHERE pr.Username = @Username
AND p.IsPersonalPost = 1
DECLARE @independentPostExists BIT = CASE
WHEN EXISTS (SELECT 1 FROM Post t
WHERE t.Independent = 1 AND t.PostID > 0)
THEN 1
ELSE 0
END
DECLARE @temp0 TABLE (
DocumentID int
, Likeness int
, ParentScrutinyID int
)
;With AllPost
As
(
Select pp.PostID
From
PersonPost pp
Join Person prs On prs.PersonID = pp.PersonID
Where prs.Username = @Username
Union
Select [type].PostID
From
Post [type]
Join Post p On p.TypeID = [type].PostID
Join PersonPost pp On pp.PostID = p.PostID
Join Person prs On prs.PersonID = pp.PersonID
Where prs.Username = @Username
)
,
SplitSearchText
AS
(
Select * From dbo._1001_Split(dbo.ReplaceYK(@SearchText),N'')
),
Temp0
AS
(
Select Distinct
s.DocumentID
, s.Code
, s2_Scrutiny.ParentScrutinyID
From
s2_Document s
Join s2_State state On state.StateID = s.StateID
Join Post sender On sender.PostID = s.SenderID
Join s2_Scrutiny On
s2_Scrutiny.DocumentID = s.DocumentID
And s2_Scrutiny.IsActive = 1
And s2_Scrutiny.ReferenceID not in (-10, -20)
Cross Join AllPost
Join s2_Producer On s2_Producer.DocumentID = s.DocumentID
Join PersonPost producerPost On producerPost.PostID = s2_Producer.PostID
Join Person producerPerson On producerPerson.PersonID = producerPost.PersonID
Where
1 = 1
And (@States = '' Or (N',' + @States + N',') Like (N'%,' + Cast(s.StateID as nvarchar(max)) + ',%'))
And (@Senders = '' Or (N',' + @Senders + N',') Like (N'%,' + Cast(s.SenderID as nvarchar(max)) + ',%'))
And (@Date1 = '' Or s.RegistrationDate >= @Date1)
And (@Date2 = '' Or s.RegistrationDate <= @Date2)
And (@Filter1ID = ''
Or Exists(
Select 1
From
s2_FieldValue fv
Join s2_Field f On f.FieldID = fv.FieldID
Where
fv.DocumentID = s.DocumentID
And fv.FieldID = @Filter1ID
And (
(f.FieldTypeID in (0, 5/*فیلد محاسباتی*/) And fv.[Value] = @Filter1Value)
Or (f.FieldTypeID = 3 And Cast(fv.[FieldOptionID] as nvarchar(max)) = @Filter1Value)
Or (f.FieldTypeID in(1,2,4))
)
))
--پیشنهاد به پست یا نوع پستی که این شخص حائز آن است، ارجاع شده است
And AllPost.PostID = s2_Scrutiny.ReferenceID
), Temp1
AS
(
Select Distinct
s.DocumentID
,Likeness = 99999999
From Temp0 s
Where @SearchText != '' And @SearchText = ISNULL(s.Code, s.DocumentID)
Union
Select Distinct
s.DocumentID
,Likeness = SUM(ts.[Length])
From
Temp0 s
Join s2_TextSegment ts On
ts.TableName = N's2_Document'
And ts.FieldName = N'Subject'
And ts.RecordID = s.DocumentID
Where @SearchText != '' And @SearchText != ISNULL(s.Code, s.DocumentID)
Group by s.DocumentID
Union
Select Distinct
s.DocumentID
,Likeness = 1
From Temp0 s
Where @SearchText = ''
)
, Temp2
AS
(
Select t0.*, t1.Likeness
From
Temp0 t0
Join Temp1 t1 On t0.DocumentID = t1.DocumentID
)
Insert Into @temp0 (DocumentID, Likeness, ParentScrutinyID)
Select DocumentID, Likeness, ParentScrutinyID From Temp2
DECLARE @temp1 TABLE (
DocumentID int
, Likeness int
)
If @independentPostExists = 0
Begin
Insert Into @temp1 (DocumentID, Likeness)
Select
t.DocumentID
, t.Likeness
From
@temp0 t
End
ELSE
Begin--حوزه مستقلی تعریف شده باشد
--انتقال حوزه فعال باشد
Insert Into @temp1 (DocumentID, Likeness)
Select
t.DocumentID
, t.Likeness
From
@temp0 t
Join s2_Scrutiny parentScrutiny On parentScrutiny.ScrutinyID = t.ParentScrutinyID
Join s2_ScrutinyItem sci On sci.ScrutinyItemID = parentScrutiny.ScrutinyItemID
Where
sci.TransferArea = 1
-- شخص جاری در حوزه ارجاع دهنده باشد
Insert Into @temp1 (DocumentID, Likeness)
Select
t.DocumentID
, t.Likeness
From
@temp0 t
Join s2_Scrutiny parentScrutiny On parentScrutiny.ScrutinyID = t.ParentScrutinyID
Join Temp_SubalternPost tsp1 On tsp1.Subaltern_PostID = parentScrutiny.ScrutinierID
Join Temp_SubalternPost tsp2 On tsp2.Superior_PostID = tsp1.Superior_PostID
Where
tsp1.Superior_NearestIndependent = 1
And tsp2.Subaltern_PostID = @PersonalPostID
--And Not Exists(Select 1 From @temp0 tt Where tt.DocumentID = t.DocumentID)
End
Select Count(Distinct t.DocumentID) From @temp1 t Where Likeness > 0
END--end procedure
GO
在这段代码中,我删除了exec sp_executesql N'Exec [dbo].[s2_GetReceivedDocumentsCount] @username=N'admin', @Filter1ID=N'12',@Filter1Value=N'17658'
当我删除此exec sp_executesql N'Exec [dbo].[s2_GetReceivedDocumentsCount] @username=N'admin'
时,请不要在此处输入
@Filter1ID=N'12',@Filter1Value=N'17658'
现在我确定问题出在这里。但是在哪呢?问题出在哪里?
答案 0 :(得分:1)
尽管相关的EXISTS
子句可能是一个真正的问题,但是您的总体SP简直是令人难以忍受的早餐,我认为您应该首先关注其他方面:
LIKE
来匹配数字列表:
(N',' + @States + N',') Like (N'%,' + Cast(s.StateID as nvarchar(max)) + ',%'))
由于您已经使用了字符串拆分功能,因此应将输入值拆分为一个stateIDs的表变量(确保数据类型与s.StateID
相同,并将其联接。对@Senders
执行相同的操作
尽量减少使用OR
,因为这会很快导致性能下降:
此And (@Date1 = '' Or s.RegistrationDate >= @Date1)
应替换为:
SET @Date1 = CASE WHEN '' THEN '01-Jan-1753' ELSE @Date1 END
,然后在查询中只需输入And s.RegistrationDate >= @Date1
。
对于@Date2
,请根据DATETIME参考使用最大值。
摆脱NVARCHAR( MAX )
。除非您实际希望输入值超过4000个字符,否则应使用NVARCHAR( 2000 )
或更小的字符。
UNION
和UNION ALL
之间存在很大的性能差异。除非您需要删除重复的记录,否则请确保使用UNION ALL
。参见this
最后EXISTS
:在不完全了解您的表结构并不能自己运行查询的情况下,我看不到删除它的方法,这样肯定会提高性能。