2017-07-06 232 views
0

我正在使用SQL Server 2012,我有一個查詢的搜索目的,但它需要太長的時間來執行..(30行= 6秒)SQL Server查詢太慢,缺少索引?

我已經檢查了執行計劃,但他沒有建議把索引,我不知道我可以如何加快查詢。

這裏是我的查詢:

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的執行計劃:

enter image description here

編輯:

這裏是我的查詢計劃網址: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

真的很難讀你在截圖的形式規劃。你可以使用這個:https://www.brentozar.com/pastetheplan/?我假設你在ID字段上有聚簇索引,但Langue和PaysISOChar3字段上的索引是什麼? –

+0

@JacobH我把我的查詢計劃在我的問題感謝information.PaysISOChar3字段這些都是varchar字段。 – alexandre

+0

平時對搜索查詢有where子句,這似乎是在返回表的一切。你在應用程序中過濾嗎? – Jesse

回答

1

閱讀這麼長的查詢計劃真的非常費時。你不得不提及涉及的記錄數。

我)聚集索引掃描 - 它告訴列是CI,但指標沒有被利用

一)由於條件不關心是否可優化搜索欄像

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

同樣,在其他places.Even不索引然後也改變它到這個。

b)同樣,當有很高的心臟估計值時,索引就不會被使用。

II)我在這外毫無疑問應用BB查詢.ARe你相信你會再次使用tbRVObjet A這裏面外申請,也可以直接加入從上述主要tbRVObjet

III)希望所有的列使用連接條件爲int,位,日期等。如果存在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)當你點評訂單時會發生什麼,你不能沒有它嗎?

六)如果你可以把dbo.fn_GetFirstIDRVObjet代碼也在裏面外適用。

七)重新檢查連接條件內outer apply tbAdresse .Are你肯定沒有多餘的加入condition.I有懷疑這些表是這裏面外應用之間的相互關係。

八)這是vety清楚,onlyFirst爲0或1,從而以書面And isnull(onlyFirst,0) = 1沒有意義的,簡單的寫And(onlyFirst = 1

IX)檢查括號這裏的DIFF與自己的

((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前綴大多數places.Also的使用With (Nolock)

我認爲你可以註釋掉所有外部應用及其column.Run查詢檢查計劃,修復索引微調查詢然後開始uncommneting外申請逐一重複這個過程。

0

視圖請確保您有對連接上的字段,外鍵索引,並在WHERE子句中的字段。您可以通過將字段放在索引的INCLUDE(葉級)的SELECT中來創建一個覆蓋索引。查看現有索引以確保不會創建重疊索引。嘗試添加以下查詢提示以確保您的系統不是CPU瓶頸:OPTION(MAXDOP 1,RECOMPILE),這將強制執行一個序列計劃。有時候這也會給你新的索引建議。