多表的慢速 SQL 查询
Posted
技术标签:
【中文标题】多表的慢速 SQL 查询【英文标题】:Slow SQL Query with many tables 【发布时间】:2021-10-14 09:17:34 【问题描述】:我是SQL
问题中的新生,非常感谢您的帮助。我收到了一个查询(不是我写的),运行 550 000 行需要将近 15 分钟,所以我想改进它,但我看不出如何。
按照查询,我尝试仅使用 2021 年的数据进行过滤,但它不起作用...
谢谢大家支持!!祝你好运!
Select
d.*, --BD dbo.Documents (23 496 430)
case when d.DateStartStaging >0 then d.DateStartStaging else d.DateArchived end as CreatedDate,
year(DateArchived) as Year,
month(DateArchived) as Month,
cast(DateArchived as date) as DateArchivedAux
From (select distinct
c.Name as InvestorName,
dc.ClientId,
lp.Judicialfile,
d.id as DocumentId,
lkp.Name + isnull('/'+lk2.name,'') as DocumentType,
lkp.Name AS DocumentName,
lk2.Name AS DocumentSubCode,
lda.Description AS ArchiveStatusCodeName,
case when h.ArchiveStatusCode = '0' then isnull(uc.DelegatorDisplayName,uc.DisplayName) else isnull(ud.DelegatorDisplayName,ud.DisplayName) end as Nome,
di.CreatedDate as DocumentDate,
case when h.ArchiveStatusCode = '0' then h.StatusDate else null end as DateStartStaging,
h.ActivityDate,
case when h.ArchiveStatusCode = '0' then he.StatusDate else h.StatusDate end as DateArchived
from HST_Documents h with (NOLOCK)
inner join vwSessions as ud with (NOLOCK) on h.SessionId = ud.Id
left join HST_Documents as he with (NOLOCK) on h.DocumentId = he.DocumentId and he.StatusDate >= h.StatusDate and (he.PreviousArchiveStatusCode = '0' and he.ArchiveStatusCode = '1') and he.IsActive=1
inner join Documents as d with (NOLOCK) on h.DocumentId = d.Id and d.IsActive=1
left join LKP_Documents as lkp with (NOLOCK) on d.DocumentCode = lkp.Code and lkp.IsActive=1
left join LKP_Documents as lk2 with (NOLOCK) on d.DocumentSubCode = lk2.Code and lk2.IsActive=1
left join DocumentsClients as dc with (NOLOCK) on d.id = dc.DocId
left join vwContacts as c with (NOLOCK) on d.InvestorId = c.Id
left join vwSessions as uc with (NOLOCK) on he.SessionId = uc.Id
left join (select
llp.LegalProcessId,
lp.JudicialFile,
c.InvestorId
from LegalProcesses AS lp WITH(NOLOCK)
Inner Join dbo.LoanLegalProcesses AS llp WITH(NOLOCK) ON llp.LegalProcessId = lp.Id and llp.isactive=1
Inner Join dbo.Loans AS l WITH(NOLOCK) ON llp.LoanId = l.Id
Inner Join dbo.Clients AS c WITH(NOLOCK) ON l.ClientId = c.Id
where lp.isactive=1
) as lp on lp.LegalProcessId = d.LegalProcessId and lp.InvestorId=d.investorid
left join LKP_DocumentArchiveStatus as lda WITH (NOLOCK) ON h.ArchiveStatusCode = lda.Code
left join DocumentInfo di WITH(NOLOCK) ON h.DocumentId=di.id
where (he.StatusDate >= '2021-01-01' or h.StatusDate >= '2021-01-01')
and h.IsActive = 1
and ((h.ArchiveStatusCode = '0' AND ISNULL(h.PreviousArchiveStatusCode,'-') <> '0') or (h.ArchiveStatusCode = '1'
and h.PreviousArchiveStatusCode is null))
) as d
where d.ActivityDate >= '2021-01-01' -- filtro de data 2021
and DocumentName in ('AM DOC' ,'BORROWER DOC' ,'LEGAL DOC' , 'ARQUIVO','Notificação' ,'Requerimento')
and Nome in ( 'Ligia Pacheco',
'Margarida Silva',
'Claudia Matos',
'Silvia Pinto',
'Vanessa Carvalho',
'Nidea Pires',
'Ana Cristina Louro',
'Soraia Frias',
'Maria Isabel Eusebio',
'Ines Melo',
'Sergio Xavier',
'Natacha Natu',
'Sandra Goncalves',
'Mariana Silva',
'Andreia Filipa Paiva') --filtro por users
【问题讨论】:
使用 NOLOCK 向您的代码发送垃圾邮件是一个非常糟糕的主意。还请为该查询生成一个执行计划,并使用此网站或类似网站分享它:brentozar.com/pastetheplan(编辑您的问题并将链接添加到您的计划那里。) Tks @MatBailie,但我没有访问权限(它在我的 MSSMS 中不可用,我的用户配置文件不允许使用它)。还有其他方法可以帮助我吗? 您可以在查询之前添加一些选项来添加统计信息和SHOWPLANSET STATISTICS IO ON; SET STATISTICS TIME ON; SET SHOWPLAN_XML ON;
嗨@ThiagoBellas 我认为您至少应该尝试更好地格式化 SQL 代码并提供一些涉及的表模式,以便我们可以更好地理解这里的问题
请不要将这些添加为 cmets。 编辑您的问题,并将信息作为格式化文本发布到那里。
【参考方案1】:
提高性能的一个快速修改是在子查询中移动过滤器。
不同的操作非常消耗性能。 在您的情况下, Distinct 在第二个 where 之前启动。
(第一个 where -> distinct -> 第二个 where)
结合两个条件的示例where:
Select
d.*, --BD dbo.Documents (23 496 430)
case when d.DateStartStaging >0 then d.DateStartStaging else d.DateArchived end as CreatedDate,
year(DateArchived) as Year,
month(DateArchived) as Month,
cast(DateArchived as date) as DateArchivedAux
From (select distinct
c.Name as InvestorName,
dc.ClientId,
lp.Judicialfile,
d.id as DocumentId,
lkp.Name + isnull('/'+lk2.name,'') as DocumentType,
lkp.Name AS DocumentName,
lk2.Name AS DocumentSubCode,
lda.Description AS ArchiveStatusCodeName,
case when h.ArchiveStatusCode = '0' then isnull(uc.DelegatorDisplayName,uc.DisplayName) else isnull(ud.DelegatorDisplayName,ud.DisplayName) end as Nome,
di.CreatedDate as DocumentDate,
case when h.ArchiveStatusCode = '0' then h.StatusDate else null end as DateStartStaging,
h.ActivityDate,
case when h.ArchiveStatusCode = '0' then he.StatusDate else h.StatusDate end as DateArchived
from HST_Documents h with (NOLOCK)
inner join vwSessions as ud with (NOLOCK) on h.SessionId = ud.Id
left join HST_Documents as he with (NOLOCK) on h.DocumentId = he.DocumentId and he.StatusDate >= h.StatusDate and (he.PreviousArchiveStatusCode = '0' and he.ArchiveStatusCode = '1') and he.IsActive=1
inner join Documents as d with (NOLOCK) on h.DocumentId = d.Id and d.IsActive=1
left join LKP_Documents as lkp with (NOLOCK) on d.DocumentCode = lkp.Code and lkp.IsActive=1
left join LKP_Documents as lk2 with (NOLOCK) on d.DocumentSubCode = lk2.Code and lk2.IsActive=1
left join DocumentsClients as dc with (NOLOCK) on d.id = dc.DocId
left join vwContacts as c with (NOLOCK) on d.InvestorId = c.Id
left join vwSessions as uc with (NOLOCK) on he.SessionId = uc.Id
left join (select
llp.LegalProcessId,
lp.JudicialFile,
c.InvestorId
from LegalProcesses AS lp WITH(NOLOCK)
Inner Join dbo.LoanLegalProcesses AS llp WITH(NOLOCK) ON llp.LegalProcessId = lp.Id and llp.isactive=1
Inner Join dbo.Loans AS l WITH(NOLOCK) ON llp.LoanId = l.Id
Inner Join dbo.Clients AS c WITH(NOLOCK) ON l.ClientId = c.Id
where lp.isactive=1
) as lp on lp.LegalProcessId = d.LegalProcessId and lp.InvestorId=d.investorid
left join LKP_DocumentArchiveStatus as lda WITH (NOLOCK) ON h.ArchiveStatusCode = lda.Code
left join DocumentInfo di WITH(NOLOCK) ON h.DocumentId=di.id
where (he.StatusDate >= '2021-01-01' or h.StatusDate >= '2021-01-01')
and h.IsActive = 1
and ((h.ArchiveStatusCode = '0' AND ISNULL(h.PreviousArchiveStatusCode,'-') <> '0') or (h.ArchiveStatusCode = '1'
and h.PreviousArchiveStatusCode is null))
and h.ActivityDate >= '2021-01-01' -- filtro de data 2021
and lkp.Name in ('AM DOC' ,'BORROWER DOC' ,'LEGAL DOC' , 'ARQUIVO','Notificação' ,'Requerimento')
and ((h.ArchiveStatusCode = '0' and isnull(uc.DelegatorDisplayName,uc.DisplayName)in ( 'Ligia Pacheco',
'Margarida Silva',
'Claudia Matos',
'Silvia Pinto',
'Vanessa Carvalho',
'Nidea Pires',
'Ana Cristina Louro',
'Soraia Frias',
'Maria Isabel Eusebio',
'Ines Melo',
'Sergio Xavier',
'Natacha Natu',
'Sandra Goncalves',
'Mariana Silva',
'Andreia Filipa Paiva'))
OR (h.ArchiveStatusCode != '0' and isnull(ud.DelegatorDisplayName,ud.DisplayName)in ( 'Ligia Pacheco',
'Margarida Silva',
'Claudia Matos',
'Silvia Pinto',
'Vanessa Carvalho',
'Nidea Pires',
'Ana Cristina Louro',
'Soraia Frias',
'Maria Isabel Eusebio',
'Ines Melo',
'Sergio Xavier',
'Natacha Natu',
'Sandra Goncalves',
'Mariana Silva',
'Andreia Filipa Paiva')))
) as d
您也可以在第二个 where 条件之后应用 distinct。
在 where 两个条件之后启动 distinct 的示例:
Select distinct
d.*, --BD dbo.Documents (23 496 430)
case when d.DateStartStaging >0 then d.DateStartStaging else d.DateArchived end as CreatedDate,
year(DateArchived) as Year,
month(DateArchived) as Month,
cast(DateArchived as date) as DateArchivedAux
From (select
c.Name as InvestorName,
dc.ClientId,
lp.Judicialfile,
d.id as DocumentId,
lkp.Name + isnull('/'+lk2.name,'') as DocumentType,
lkp.Name AS DocumentName,
lk2.Name AS DocumentSubCode,
lda.Description AS ArchiveStatusCodeName,
case when h.ArchiveStatusCode = '0' then isnull(uc.DelegatorDisplayName,uc.DisplayName) else isnull(ud.DelegatorDisplayName,ud.DisplayName) end as Nome,
di.CreatedDate as DocumentDate,
case when h.ArchiveStatusCode = '0' then h.StatusDate else null end as DateStartStaging,
h.ActivityDate,
case when h.ArchiveStatusCode = '0' then he.StatusDate else h.StatusDate end as DateArchived
from HST_Documents h with (NOLOCK)
inner join vwSessions as ud with (NOLOCK) on h.SessionId = ud.Id
left join HST_Documents as he with (NOLOCK) on h.DocumentId = he.DocumentId and he.StatusDate >= h.StatusDate and (he.PreviousArchiveStatusCode = '0' and he.ArchiveStatusCode = '1') and he.IsActive=1
inner join Documents as d with (NOLOCK) on h.DocumentId = d.Id and d.IsActive=1
left join LKP_Documents as lkp with (NOLOCK) on d.DocumentCode = lkp.Code and lkp.IsActive=1
left join LKP_Documents as lk2 with (NOLOCK) on d.DocumentSubCode = lk2.Code and lk2.IsActive=1
left join DocumentsClients as dc with (NOLOCK) on d.id = dc.DocId
left join vwContacts as c with (NOLOCK) on d.InvestorId = c.Id
left join vwSessions as uc with (NOLOCK) on he.SessionId = uc.Id
left join (select
llp.LegalProcessId,
lp.JudicialFile,
c.InvestorId
from LegalProcesses AS lp WITH(NOLOCK)
Inner Join dbo.LoanLegalProcesses AS llp WITH(NOLOCK) ON llp.LegalProcessId = lp.Id and llp.isactive=1
Inner Join dbo.Loans AS l WITH(NOLOCK) ON llp.LoanId = l.Id
Inner Join dbo.Clients AS c WITH(NOLOCK) ON l.ClientId = c.Id
where lp.isactive=1
) as lp on lp.LegalProcessId = d.LegalProcessId and lp.InvestorId=d.investorid
left join LKP_DocumentArchiveStatus as lda WITH (NOLOCK) ON h.ArchiveStatusCode = lda.Code
left join DocumentInfo di WITH(NOLOCK) ON h.DocumentId=di.id
where (he.StatusDate >= '2021-01-01' or h.StatusDate >= '2021-01-01')
and h.IsActive = 1
and ((h.ArchiveStatusCode = '0' AND ISNULL(h.PreviousArchiveStatusCode,'-') <> '0') or (h.ArchiveStatusCode = '1'
and h.PreviousArchiveStatusCode is null))
) as d
where d.ActivityDate >= '2021-01-01' -- filtro de data 2021
and DocumentName in ('AM DOC' ,'BORROWER DOC' ,'LEGAL DOC' , 'ARQUIVO','Notificação' ,'Requerimento')
and Nome in ( 'Ligia Pacheco',
'Margarida Silva',
'Claudia Matos',
'Silvia Pinto',
'Vanessa Carvalho',
'Nidea Pires',
'Ana Cristina Louro',
'Soraia Frias',
'Maria Isabel Eusebio',
'Ines Melo',
'Sergio Xavier',
'Natacha Natu',
'Sandra Goncalves',
'Mariana Silva',
'Andreia Filipa Paiva') --filtro por users
您还可以通过定义事务级别(在查询之前)避免对每个表使用with (NOLOCK)
set transaction level read uncommitted
【讨论】:
如果您使用 SSMS(Microsoft 的 SQL Server Management Studio),此提示适合您:右键单击查询窗口,然后选择显示实际执行计划,然后运行查询。执行计划显示有时会建议创建一个新索引。以上是关于多表的慢速 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章