这是我的疑问:
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
数据库中几乎没有100,000条记录,但此查询大约需要2秒才能获取50条记录。完全不能接受!我甚至在大多数使用连接的列上都有索引。
在CTE的基本子句中进行单个连接,但这是必需的。我知道联盟是杀手,但我需要加入。如果删除这段代码:
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子句是决定因素。类型为varchar(14)的OldInstrumentID
速度很慢,需要2秒,而如果我按类型为d.DocumentID
进行排序,则即使我保留所有这些冗余条件,它也能在0秒内正常工作
这是我的执行计划:
更新
我在每一列上都创建了这样的索引,它似乎运行得非常快。 Woot Woot !!!
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]
)
答案 0 :(得分:1)
条件可能导致查询速度变慢的原因有几个:
正如另一个注释,应该删除“WHERE 1 = 1”语句,因为它们将强制SQL Server引擎检索并处理我认为的所有行 - 您可能正在使用此内核查询优化句法。
答案 1 :(得分: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)
上创建索引,以便索引用于此部分。
答案 2 :(得分: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
这是否有必要?
加入用户u.UserID = u.UserID
如果你是FK那么这将永远是真的
答案 3 :(得分:-1)
我会尝试将DocumentstatusID
,JurisdictionID
和CreatedByJurisdictionID
作为CTE中的列,并将非常复杂的join子句作为最终连接的WHERE。
我并不感到惊讶,因为所有这些&#39;不等于&#39;案例和复杂的逻辑,作为一个不等于&#39;本身并不是一个快速的操作。我试图简化所有代码。