提供以提高存储过程的性能

时间:2019-07-29 18:48:08

标签: sql sql-server stored-procedures

我在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'

现在我确定问题出在这里。但是在哪呢?问题出在哪里?

1 个答案:

答案 0 :(得分:1)

尽管相关的EXISTS子句可能是一个真正的问题,但是您的总体SP简直是令人难以忍受的早餐,我认为您应该首先关注其他方面:

  1. 请勿使用LIKE来匹配数字列表: (N',' + @States + N',') Like (N'%,' + Cast(s.StateID as nvarchar(max)) + ',%'))

由于您已经使用了字符串拆分功能,因此应将输入值拆分为一个stateIDs的表变量(确保数据类型与s.StateID相同,并将其联接。对@Senders执行相同的操作

  1. 尽量减少使用OR,因为这会很快导致性能下降:

    And (@Date1 = '' Or s.RegistrationDate >= @Date1)应替换为: SET @Date1 = CASE WHEN '' THEN '01-Jan-1753' ELSE @Date1 END,然后在查询中只需输入And s.RegistrationDate >= @Date1

对于@Date2,请根据DATETIME参考使用最大值。

  1. 摆脱NVARCHAR( MAX )。除非您实际希望输入值超过4000个字符,否则应使用NVARCHAR( 2000 )或更小的字符。

  2. UNIONUNION ALL之间存在很大的性能差异。除非您需要删除重复的记录,否则请确保使用UNION ALL。参见this

  3. 最后EXISTS:在不完全了解您的表结构并不能自己运行查询的情况下,我看不到删除它的方法,这样肯定会提高性能。

    < / li>
相关问题