【问题标题】:SQL Server Query too slow missing index?SQL Server 查询太慢缺少索引?
【发布时间】:2017-07-06 13:45:45
【问题描述】:

我正在使用 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 中的执行计划:

编辑:

这是我的查询计划 URL: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 是上面查询的视图

【问题讨论】:

  • 真的很难以屏幕截图的形式阅读您的计划。你可以使用这个:brentozar.com/pastetheplan 吗?我将假设您在 ID 字段上有聚集索引,但在 Langue 和 PaysISOChar3 字段上的索引是什么?
  • @JacobH 我把我的查询计划放在我的问题中谢谢你的信息。PaysISOChar3 字段这些是 varchar 字段。
  • 通常在搜索查询中有 where 子句,这似乎是返回表中的所有内容。您是否在应用程序中进行过滤?

标签: jquery sql sql-server search indexing


【解决方案1】:

阅读这么长的查询计划真的很费时间。

您必须提及涉及的记录数。

i) 聚集索引扫描 - 它告诉列是 CI,但索引没有被利用

a) 因为条件不像 SARGable

ISNULL(tbRVObjet.IsForfaitEntete, 0) = 1 
instead write `(tbRVObjet.IsForfaitEntete = 1 )`

在其他地方也类似。即使关注列不是索引,也将其更改为这个。

b) 此外,当基数估计值较高时,则不使用索引。

ii) 我对这个外部 Apply BB 查询毫无疑问。你确定你会在这个外部应用中再次使用 tbRVObjet A 或者你可以直接从上面的 main 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) 当你注释掉 order by 时会发生什么,你不能没有它吗?

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)

我认为您可以注释掉所有外部应用及其列。运行查询检查计划,修复索引微调查询然后开始一一取消外部应用并重复该过程。

【讨论】:

    【解决方案2】:

    确保您在 JOIN ON 字段、外键和 WHERE 子句中的字段上有索引。您可以通过将字段放在索引的 INCLUDE(叶级别)中的 SELECT 中来创建覆盖索引。查看现有索引以确保您没有创建重叠索引。尝试添加以下查询提示以确保您的系统没有 CPU 瓶颈:OPTION (MAXDOP 1, RECOMPILE),这将强制执行串行计划。有时这也会为您提供新的索引建议。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-06
      • 1970-01-01
      • 2019-09-24
      • 2017-03-29
      • 2021-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多