带有“选择 x 不为空”的 SQL Server 视图需要很长时间才能完成
Posted
技术标签:
【中文标题】带有“选择 x 不为空”的 SQL Server 视图需要很长时间才能完成【英文标题】:SQL Server view with a 'select where x is not null' takes ages to complete 【发布时间】:2011-04-07 13:34:41 【问题描述】:我有一个复杂的视图,这里描述:View of multiple tables. Need to remove "doubles" defined by 1 table
我在其中使用了Cross Apply
,代码是这样的:(请查看上面的网址以了解视图)
SELECT dbo.InstellingGegevens.INST_SUBTYPE
, dbo.InstellingGegevens.INST_BRON
, dbo.InstellingGegevens.INST_INSTELLINGSNUMMER
, dbo.InstellingGegevens.INST_NAAM
, dbo.InstellingGegevens.INST_KORTENAAM
, dbo.InstellingGegevens.INST_VESTIGINGSNAAM
, dbo.InstellingGegevens.INST_ROEPNAAM
, dbo.InstellingGegevens.INST_STATUUT
, dbo.InstellingGegevens.ONDERWIJSNIVEAU_REF
, dbo.InstellingGegevens.ONDERWIJSSOORT_REF
, dbo.InstellingGegevens.DATUM_TOT
, dbo.InstellingGegevens.DATUM_VAN
, dbo.InstellingGegevens.VERBOND_REF
, dbo.InstellingGegevens.VSKO_LID
, dbo.InstellingGegevens.NET_REF
, dbo.Instellingen.Inst_ID
, dbo.Instellingen.INST_TYPE
, dbo.Instellingen.INST_REF
, dbo.Instellingen.INST_LOC_REF
, dbo.Instellingen.INST_LOCNR
, dbo.Instellingen.Opt_KalStandaard
, dbo.InstellingTelecom.INST_TEL
, dbo.InstellingTelecom.INST_FAX
, dbo.InstellingTelecom.INST_EMAIL
, dbo.InstellingTelecom.INST_WEB
, dbo.InstellingAdressen.SOORT
, dbo.InstellingAdressen.STRAAT
, dbo.InstellingAdressen.POSTCODE
, dbo.InstellingAdressen.GEMEENTE
, dbo.InstellingAdressen.GEM_REF
, dbo.InstellingAdressen.FUSIEGEM_REF
, dbo.InstellingAdressen.FUSIEGEM
, dbo.InstellingAdressen.ALFA_G
, dbo.InstellingAdressen.PROVINCIE
, dbo.InstellingAdressen.BISDOM
, dbo.InstellingAdressen.ARRONDISSEMENT
, dbo.InstellingAdressen.GEWEST
, dbo.InstellingContPersDirecteurs.AANSPREKING
, dbo.InstellingContPersDirecteurs.CONTACTPERSOON
, dbo.InstellingContPersDirecteurs.FUNCTIE
, InstellingLogin.Inst_Gebruikersnaam
, InstellingLogin.Inst_Concode
, InstellingLogin.Inst_DirCode
, InstellingLogin.DOSSNR
, InstellingLogin.Instelling_ID
FROM dbo.InstellingGegevens
RIGHT OUTER JOIN dbo.Instellingen
ON dbo.InstellingGegevens.INST_TYPE = dbo.Instellingen.INST_TYPE
AND dbo.InstellingGegevens.INST_REF = dbo.Instellingen.INST_REF
AND dbo.InstellingGegevens.INST_LOC_REF = dbo.Instellingen.INST_LOC_REF
AND dbo.InstellingGegevens.INST_LOCNR = dbo.Instellingen.INST_LOCNR
LEFT OUTER JOIN dbo.InstellingTelecom
ON dbo.InstellingGegevens.INST_TYPE = dbo.InstellingTelecom.INST_TYPE
AND dbo.InstellingGegevens.INST_REF = dbo.InstellingTelecom.INST_REF
AND dbo.InstellingGegevens.INST_LOC_REF = dbo.InstellingTelecom.INST_LOC_REF
LEFT OUTER JOIN dbo.InstellingAdressen
ON dbo.InstellingGegevens.INST_TYPE = dbo.InstellingAdressen.INST_TYPE
AND dbo.InstellingGegevens.INST_REF = dbo.InstellingAdressen.INST_REF
AND dbo.InstellingGegevens.INST_LOC_REF = dbo.InstellingAdressen.INST_LOC_REF
LEFT OUTER JOIN dbo.InstellingContPersDirecteurs
ON dbo.InstellingGegevens.INST_TYPE = dbo.InstellingContPersDirecteurs.INST_TYPE
AND dbo.InstellingGegevens.INST_REF = dbo.InstellingContPersDirecteurs.INST_REF
AND dbo.InstellingGegevens.INST_LOC_REF = dbo.InstellingContPersDirecteurs.INST_LOC_REF
CROSS APPLY
(SELECT TOP (1) *
FROM InstellingLogin AS il
WHERE Instellingen.INST_LOC_REF = il.Inst_Loc_REF
AND Instellingen.INST_LOCNR = il.Inst_Loc_Nr
AND Instellingen.INST_REF = il.Inst_InstellingIKON_REF
AND Instellingen.INST_TYPE = il.Inst_InstellingIKONType
ORDER BY CASE
WHEN il.datum_tot IS NULL
THEN 0 ELSE 1
END
, il.datum_tot DESC) InstellingLogin
这个视图在大约 1 秒内返回了大约 5.5k 行。这很快!
但是!
当我用 where 子句调用这个视图时:
SELECT *
FROM [Tink].[dbo].[InstellingAlleDetails]
where gemeente is not null and (DATUM_TOT is null or DATUM_TOT > GETDATE())
order by GEMEENTE, POSTCODE,STRAAT, INST_NAAM
返回所有行需要 1 分 20 秒。
当我删除 gemeente is not null
部分时,它又需要 1 秒。
Gemeente
是一个 varchar(255)。我还用Inst_Naam is not null
尝试过,也花了大约 1 分 30 秒。
为什么is not null
需要这么长时间?更重要的是:我该如何解决这个问题?
【问题讨论】:
Inst_Naam
没有出现在此视图中...正如 HLGEM 所说,您确实需要运行两个查询(有/没有 is null
条件),并比较执行计划。如果您可以确定差异,请将它们添加到您的问题中。
【参考方案1】:
我不知道为什么。可能 SQL Server 提出了一个不太好的查询计划。
您可以尝试先在没有gemeente is not null
的情况下运行查询并将结果放入临时表中,然后使用gemeente is not null
查询临时表。
select *
into #TempTable
from YourView
select *
from #TempTable
where gemeente is not null
drop table #TempTable
【讨论】:
所以这意味着创建一个表,或者有一个简单的方法来创建一个临时表? @Stefanvds - 用一些创建临时表的代码更新了答案,使用它并在完成后删除它。【参考方案2】:首先检查查询的执行计划是否为空,并查看差异。
顺便说一句,这些是否加入了其他视图?这可能会导致巨大的性能问题。
【讨论】:
是的,InstellingContPersDirecteurs
是一个观点,但这不是我认为的问题。没有cross apply
,它的工作速度很快(1s)我想它与cross apply
有关
我怀疑是CROSS APPLY
。对于如此复杂的查询(多个视图、外部连接、交叉应用,它们都加起来),您可能只是达到了这样一个点,即优化器试图从“IS NOT NULL”谓词中获得好处会导致错误的结论。将结果插入中间表,然后处理该中间表,是我个人发现的防止这种情况发生的唯一方法。以上是关于带有“选择 x 不为空”的 SQL Server 视图需要很长时间才能完成的主要内容,如果未能解决你的问题,请参考以下文章
带有 SQL Server 2019 Express 的 Windows Server 2019 上的 Hangfire
Sql Server关于create index include带有包含列的索引