-3

这是我的查询:

With cte as (
    Select
        ROW_NUMBER() OVER (Order By  d.OldInstrumentID ) peta_rn,   
        d.DocumentID
    From Documents d
    Inner Join Users u on d.UserID = u.UserID 
    Where 1=1  
       And (d.JurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9)
       And d.DocumentStatusID <> 3 And  d.DocumentStatusID <> 8 
       And  d.DocumentStatusID <> 7 
       AND ((CreatedByJurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9 Or CreatedByAccountID IN (Select AccountID From AccountsJurisdictions Where JurisdictionID = 1)))  
      And d.DocumentStatusID = 9
) 
Select
    d.DocumentID,
    d.IsReEfiled,
    d.IGroupID,
    d.ITypeID,
    d.RecordingDateTime,
    d.CreatedByAccountID,
    d.JurisdictionID, 
    Case 
        When d.OldInstrumentID IS NULL 
        THEN d.LastStatusChangedDateTime 
        Else d.RecordingDateTime 
    End as LastStatusChangedDateTime,
    dbo.FnCanChangeDocumentStatus(d.DocumentStatusID,d.DocumentID) as CanChangeStatus,
    d.IDate, 
    d.InstrumentID, 
    d.DocumentStatusID,
    d.DocumentDate,
    Upper(dbo.GetFlatDocumentName(d.DocumentID)) as FlatDocumentName
From Documents d
Inner Join cte on cte.DocumentID = d.DocumentID 
Where 1=1 
  And peta_rn>=80000 
  AND peta_rn<=80050 
Order by peta_rn

DB 中几乎没有 100,000 条记录,但此查询执行大约需要 2 秒才能获取 50 条记录。完全不能接受!我什至在大多数使用连接的列上都有索引。

在 CTE 的基本子句中进行了单个连接,但这是必需的。我知道加入是杀手,但我需要 1 加入。如果这删除这段代码:

And (d.JurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9)
And d.DocumentStatusID <> 3 
And d.DocumentStatusID <> 8 
And d.DocumentStatusID <> 7 
AND ((CreatedByJurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9 Or CreatedByAccountID IN (Select AccountID From AccountsJurisdictions Where JurisdictionID = 1))) 
And d.DocumentStatusID = 9

它运行得非常快。在 SSMS 中显示 0 秒。有什么方法可以加快这个查询?我需要这些条件,因为它们甚至没有那么大。为什么条件会减慢查询速度?我已经在 CreatedByAccountID 和其他列上有索引。真的很烦!

编辑:

感谢您的回复。更多细节:

你们中的许多人建议删除多余的条件。抱歉,这段 SQL 是在代码中动态形成的,我将该版本粘贴到 SSMS 和此处。从 where 子句中删除这些条件无济于事:

Where 1=1
  And (d.JurisdictionID = 1 Or d.DocumentStatusID = 5 Or d.DocumentStatusID = 9)
  And d.DocumentStatusID <> 3 
  And  d.DocumentStatusID <> 8 
  And  d.DocumentStatusID <> 7 
  AND ((CreatedByJurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9 Or CreatedByAccountID IN (Select AccountID From AccountsJurisdictions Where JurisdictionID = 1)))  
  And d.DocumentStatusID = 9

事实上,只要我放入 where 子句,它就会变慢。所以,即使这个也很慢:

 Where 1=1 
   And (d.JurisdictionID = 1 Or d.DocumentStatusID = 5 Or d.DocumentStatusID = 9)

更多细节。Row_Number() 中的 order by 子句是决定因素。OldInstrumentIDvarchar(14) 类型很慢,需要 2 秒,而如果我按d.DocumentIDint 类型排序,即使我保留所有这些冗余条件,它也会在 0 秒内正常工作。

这是我的执行计划:

在此处输入图像描述

更新:

我在每一列上创建了这样的索引,它似乎运行得非常快。呜呜呜!!!

Create NonClustered Index   IX_DocumentDate on Documents
(
    DocumentDate     

)
Include(
    JurisdictionID,
    JudgementTypeID,
    IDate,
    EfileDate,
    UserID,
    RecordingDateTime,
    ApprovedBy,
    ACEfileBankAccountID,
    LastStatusChangedDateTime,
    ACEfileCreditCardID,
    EfiledByUserID,
    ITypeID,
    IGroupID,
    InstrumentID,
    OldInstrumentID,
    [CreatedByJurisdictionID],
    CreatedByAccountID,
    [DocumentStatusID]      


      ,[Remarks]
      ,[InternalNotes]
      ,[ParentDocumentID]
      ,[FilingNumber]
      ,[StampData]      
      ,[Receipt]
      ,[ReceiptNo]
      ,[IsReEfiled]      
      ,[ImportedFromInstrumentID]

)
4

4 回答 4

1

这些条件可能会减慢您的查询速度有几个可能的原因:

  • 我怀疑查询引擎别无选择,只能执行索引或表扫描以从 Documents 表中获取 DocumentStatusID 的值。但是,根据我的阅读,大部分工作都是多余的,因为条件的最后一行表明 DocumentStatusID 必须始终等于 9。如果 SQL Server 引擎最后处理此条件,则可能是它正在执行更多的表扫描评估其他条件而不是它需要的。您的其他条件可能会被重写,因为您只会返回 DocumentStatusID 为 9 的文档。
  • 您的 CTE 中有一个子查询,每次请求您的 CTE 的值时都会执行该子查询。如果 AccountsJurisdictions 表很大并且 AccountID 没有被索引,那么这里可能会影响性能。

就像另一个注意事项一样,可能应该删除“WHERE 1=1”语句,因为它们将强制 SQL Server 引擎检索和处理我认为的所有行 - 您可能正在使用这种语法对抗内置查询优化。

于 2012-12-26T15:54:14.527 回答
1

您的 CTE 可以通过多种方式进行简化。特别是,您正在检查,因此可以删除d.DocumentStatusID = 9对的任何其他引用。documentStatusId

但是,我认为性能问题是由于in嵌入在复杂where逻辑中的子句所致。 In通常在 SQL Server 中优化得很好。不过,在这种情况下,我猜你得到的是一个嵌套循环连接。尝试进行显式连接:

    Select  ROW_NUMBER() OVER (Order By  d.OldInstrumentID ) peta_rn,   
            d.DocumentID
    From Documents d Inner Join
         Users u left outer join
         on d.UserID = u.UserID 
         (select distinct AccountId
          from AccountsJurisdictions
          Where JurisdictionID = 1
         ) aj1
         on u.CreatedByAccountID = aj1.AccountId and
               (d.JurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9) AND
               d.DocumentStatusID <> 3 And d.DocumentStatusID <> 8 AND
               d.DocumentStatusID <> 7 AND
               (CreatedByJurisdictionID = 1 Or DocumentStatusID = 5 
                 Or DocumentStatusID = 9 Or aj1.AccountId is not NULL
                ) AND
               d.DocumentStatusID = 9

您也可以尝试创建一个索引,AccountsJurisdictions(JurisdictionId, AccountId)以便该索引用于该部分。

于 2012-12-26T16:29:55.270 回答
0

如果 d.DocumentStatusID = 9 则有很多冗余条件

;With cte as (
               Select  ROW_NUMBER() OVER (Order By  d.OldInstrumentID ) peta_rn, d.DocumentID
               From Documents d
               Join Users u 
                    on d.UserID = u.UserID 
               Where -- 1 = 1 AND
               d.DocumentStatusID = 9 
               AND (CreatedByJurisdictionID = 1  
                    Or CreatedByAccountID IN (Select AccountID From AccountsJurisdictions Where JurisdictionID = 1)
                   )
               -- below redundant as  d.DocumentStatusID = 9
               --(d.JurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9)
               --And d.DocumentStatusID <> 3 
               --And d.DocumentStatusID <> 8 
               --And  d.DocumentStatusID <> 7 
               --AND (
               --      Or DocumentStatusID = 5 
               --      Or DocumentStatusID = 9 
               --    )  
             ) 
Select  d.DocumentID, d.IsReEfiled, d.IGroupID, d.ITypeID, d.RecordingDateTime -- ...
From Documents d 
Join cte 
  on cte.DocumentID = d.DocumentID 
Where -- 1=1 AND
     peta_rn>=80000 AND peta_rn<=80050 
Order by peta_rn

这甚至是必要的吗?
在 d.UserID = u.UserID 上加入用户 u
如果 u 是 FK,那么这将始终为真

于 2012-12-26T16:15:51.760 回答
-1

我会尝试将DocumentstatusID,JurisdictionIDCreatedByJurisdictionID作为 CTE 中的列,并将非常复杂的连接子句作为 WHERE 放在最终连接上。

对于所有那些“不等于”的情况和复杂的逻辑,我并不感到惊讶,因为“不等于”本身并不是一个快速的操作。我会尝试简化围绕这些的所有代码。

于 2012-12-26T16:07:13.803 回答