我正在使用SQL Server 2012,我有一个查询搜索目的,但执行时间太长..(30行= 6秒)
我已经检查了执行计划,但他不建议放置索引,我不知道如何加快查询速度。
这是我的疑问:
SELECT
dbo.tbRV.ID, dbo.tbRV.IDCompagnie,
dbo.tbPatient.Nom + N', ' + dbo.tbPatient.Prenom AS NomPrenomPatient,
dbo.tbRV.DateRV, dbo.tbRV.HeureDebut,
dbo.tbRV.IDRessource,
coalesce(dbo.tbRessource.Nom ,'') + ' ' + coalesce(dbo.tbRessource.Prenom,'') AS NomPrenomRessource,
dbo.tbPatient.NoApp,
dbo.tbPatient.NomEtablissement, dbo.tbPatient.Adresse1,
tbAdresse.Ville, dbo.tbPatient.TelephoneDomicile,
dbo.tbPatient.TelephoneTravail,
dbo.tbPatient.TelephonePortable,
case
when DD.id is not null then DD.description
else dbo.tbRVObjet.IDObjet
end as idobjet,
dbo.tbPatient.Nom_SansAccent, dbo.tbPatient.Prenom_SansAccent,
dbo.tbPatient.Nom, dbo.tbPatient.Prenom,
dbo.tbRV.IDPatient, dbo.tbPatient.NoAssuranceMaladie,
dbo.tbPatient.DateNaissance, dbo.tbRV.Transit, dbo.tbRV.Annuler,
tbAdresse.Pays, tbAdresse.Province, dbo.tbPatient.Adresse2,
dbo.tbPatient.CodePostal,
case
when AA.id is not null and AA.ID = tbrvobjet.ID then 1 else 0 end as onlyFirst
FROM
tbPatient
INNER JOIN
tbRV ON tbPatient.ID = tbRV.IDPatient
INNER JOIN
tbRessource ON (tbRV.IDRessource = tbRessource.ID) AND (tbRV.IDCompagnie = tbRessource.IDCompagnie)
INNER JOIN
tbRVObjet ON tbRV.ID = tbRVObjet.IDRV
OUTER APPLY
dbo.fn_GetFirstIDRVObjet(tbrv.id) AA
OUTER APPLY (SELECT A.ID, A.Description
FROM tbForfaitEntete A
WHERE A.ID = tbRVObjet.IDForfait
AND ISNULL(tbRVObjet.IsForfaitEntete, 0) = 1 ) DD
OUTER APPLY (SELECT B.Description
FROM tbRVObjet A
JOIN tbForfaitEntete B ON (A.IDForfait = B.ID AND ISNULL(A.IsForfaitEntete, 0) = 1)
WHERE AA.ID = A.id ) BB
OUTER APPLY (SELECT tbPaysISO.Pays, tbProvinceISO.Province, tbVilleISO.Ville
FROM tbPaysISO
JOIN tbProvinceISO ON (tbPaysISO.Langue = tbProvinceISO.Langue)
AND (tbPatient.ProvinceISOChar = tbProvinceISO.ProvinceISOChar)
JOIN tbVilleISO ON (tbProvinceISO.Langue = tbVilleISO.Langue)
AND (tbPatient.IdVille = tbVilleISO.IDVille)
WHERE tbPaysISO.Langue = tbpatient.CodeLangue
AND tbPaysISO.PaysISOChar3 = tbpatient.PaysISOChar3 ) tbAdresse
这是XML中的执行计划:
修改
这是我的查询计划网址:https://www.brentozar.com/pastetheplan/?id=HkVYeasNW
这是我的搜索查询:
Select
ID, IDPatient, NomPrenomPatient, DateNaissance, NoAssuranceMaladie,
NomEtablissement, Adresse1, Adresse2, NoApp, ville, province, pays,
CodePostal, TelephoneDomicile, TelephoneTravail, TelephonePortable,
DateRV, HeureDebut, IDObjet, IDRessource, NomPrenomRessource,
Annuler, Transit
From
rqAfficheRechercheRV
Where
IDCompagnie = 1
And (isnull(NomPrenomRessource, '') + isnull(NoApp, '') + isnull(NomEtablissement, '') + isnull(Adresse1, '') + isnull(Ville, '') + isnull(TelephoneDomicile, '') + isnull(TelephoneTravail, '') + isnull(TelephonePortable, '') + isnull(IDObjet, '') + isnull(Nom_SansAccent, '') + isnull(Prenom_SansAccent, '') + isnull(Nom, '') + isnull(Prenom, '') + isnull(IDPatient, '') + isnull(NoAssuranceMaladie, '') + isnull(convert(varchar, DateNaissance), '') + isnull(Pays, '') + isnull(Province, '') + isnull(Adresse2, '') + isnull(CodePostal, '')) like '%881-1360%'
And isnull(onlyFirst,0) = 1
Order by
Nom, Prenom, DateRV DESC, HeureDebut ASC
rqAfficheRechercheRV是上面查询的视图
答案 0 :(得分:1)
阅读如此长的查询计划确实非常耗时。
你必须提到涉及的记录数量。
i)聚集索引扫描 - 它告诉该列是CI但索引未被利用
a)因为条件不像SARG那样
ISNULL(tbRVObjet.IsForfaitEntete, 0) = 1
instead write `(tbRVObjet.IsForfaitEntete = 1 )`
同样在其他地方。即使关注列不是索引,也要将其更改为此。
b)此外,当有高度的心率估计值时,索引不会被使用。
ii)我对此外部应用BB查询毫无疑问。确定您将在此外部申请中再次使用tbRVObjet A
,或者您可以直接从主要tbRVObjet
iii)希望在连接条件中使用的所有列都是int,bit,date等。如果有varchar列,则表示DB设计也存在问题。
iv)当这个东西真的属于视图时,为什么不在里面连接它 查看自己,And (isnull(NomPrenomRessource, '') + isnull(NoApp, '') + isnull(NomEtablissement, '') + isnull(Adresse1, '') + isnull(Ville, '') + isnull(TelephoneDomicile, '') + isnull(TelephoneTravail, '') + isnull(TelephonePortable, '') + isnull(IDObjet, '') + isnull(Nom_SansAccent, '') + isnull(Prenom_SansAccent, '') + isnull(Nom, '') + isnull(Prenom, '') + isnull(IDPatient, '') + isnull(NoAssuranceMaladie, '') + isnull(convert(varchar, DateNaissance), '') + isnull(Pays, '') + isnull(Province, '') + isnull(Adresse2, '') + isnull(CodePostal, '')) like '%881-1360%'
我在这里有疑问。
v)当你评论订单时会发生什么,没有它你会不会这样做?
vi)如果您可以将dbo.fn_GetFirstIDRVObjet
的代码也放在外部申请中。
vii)重新检查outer apply tbAdresse
内的连接条件。确定没有额外的连接条件。我怀疑它们在这个外部应用中的这些表之间的关系。
viii)很明显onlyFirst
为0或1,所以写And isnull(onlyFirst,0) = 1
没有意义,只需写And(onlyFirst = 1
ix)使用您自己的
检查括号中的差异((tbRV.IDRessource = tbRessource.ID) AND (tbRV.IDCompagnie = tbRessource.IDCompagnie))
在这里
((tbPaysISO.Langue = tbProvinceISO.Langue)
AND (tbPatient.ProvinceISOChar = tbProvinceISO.ProvinceISOChar))
JOIN tbVilleISO ON ((tbProvinceISO.Langue = tbVilleISO.Langue)
AND (tbPatient.IdVille = tbVilleISO.IDVille))
WHERE tbPaysISO.Langue = tbpatient.CodeLangue
AND tbPaysISO.PaysISOChar3 = tbpatient.PaysISOChar3
x)您在大多数地方都缺少dbo前缀。还要使用With (Nolock)
我认为你可以注释掉所有外部申请和他们的专栏。运行查询检查计划,修复索引微调查询然后开始uncommneting外部逐个申请并重复该过程。
答案 1 :(得分:0)
确保在WHERE子句中的JOIN ON字段,外键和字段上有索引。您可以通过在索引的INCLUDE(叶级别)中的SELECT中放置字段来创建覆盖索引。查看现有索引以确保不创建重叠索引。尝试添加以下查询提示,以确保您的系统不是CPU瓶颈:OPTION(MAXDOP 1,RECOMPILE),将强制执行串行计划。有时,这也会为您提供新的索引建议。