2009-03-02 5 views
1

Ich habe diese Abfrage, die ziemlich lang ist, aber eine Where-Klausel hinzufügen, oder Beitritt zu einer Zeichenfolge macht es zusätzliche 2 Sekunden zu laufen. Ich kann nicht herausfinden warum.Beitritt auf Varchar (50) Fremdschlüssel verlangsamt Abfrage

Hier ist die Abfrage in voller Länge:

ALTER PROCEDURE [dbo].[RespondersByPracticeID] 
    @practiceID int = null, 
    @activeOnly bit = 1 
AS 
BEGIN 
    SET NOCOUNT ON; 
    select 
     isnull(sum(isResponder),0) as [Responders] 
     ,isnull(count(*) - sum(isResponder),0) as [NonResponders] 
     ,isnull((select 
       count(p.patientID) 
      from patient p 
       inner join practice on practice.practiceid = p.practiceid 
          inner join [lookup] l on p.dosing = l.lookupid and l.lookupid = 'da_ncd' 
       where 
       p.practiceID = isnull(@practiceID, p.practiceID) 
       and p.active = case @activeOnly when 1 then 1 else p.active end 
      ) - (isnull(sum(isResponder),0) + isnull(count(*) - sum(isResponder),0)),0) 
     as [Undetermined] 
    from ( 
     select 
      v.patientID 
      ,firstVisit.hbLevel as startHb 
      ,maxHbVisit.hblevel as maxHb 
      , case when (maxHbVisit.hblevel - firstVisit.hbLevel >= 1) then 1 else 0 end as isResponder 
      ,count(v.patientID) as patientCount 
     from patient p 
      inner join visit v on v.patientid = v.patientid 
      inner join practice on practice.practiceid = p.practiceid 
      inner join [lookup] l on p.dosing = l.lookupid and l.lookupid = 'da_ncd' 
      inner join (
       SELECT 
        p.PatientID 
        ,v.VisitID 
        ,v.hblevel 
        ,v.VisitDate 
       FROM Patient p 
        INNER JOIN Visit v ON p.PatientID = v.PatientID 
       WHERE 
        v.VisitDate = (
         SELECT MIN(VisitDate) 
         FROM Visit 
         WHERE PatientId = p.PatientId 
        ) 
      ) firstVisit on firstVisit.patientID = v.patientID 
      inner join (
       select 
        p.patientID 
        ,max(v.hbLevel) as hblevel 
       from Patient p 
        INNER JOIN Visit v ON p.PatientID = v.PatientID 
       group by 
        p.patientID 
      ) MaxHbVisit on maxHbVisit.patientid = v.patientId 
     where 
      p.practiceID = isnull(@practiceID, p.practiceID) 
      and p.active = case @activeOnly when 1 then 1 else p.active end 

     group by 
      v.patientID 
      ,firstVisit.hbLevel 
      ,maxHbVisit.hblevel 
     having 
      datediff(
       d, 
       dateadd(
        day 
        ,-DatePart(
         dw 
         ,min(v.visitDate) 
        ) + 1 
        ,min(v.visitDate) 
       ) 
       , max(v.visitDate) 
      ) >= (7 * 8) -- Eight weeks. 
    ) responders 
END 

Die Linie, die es verlangsamt ist:

inner join [lookup] l on p.dosing = l.lookupid and l.lookupid = 'da_ncd' 

Auch an die where Klausel bewegt die gleiche Wirkung hat:

where p.dosing = 'da_ncd' 

Andernfalls wird die Abfrage fast sofort ausgeführt. >.<

+0

ist l.lookupid indiziert? – sfossen

+0

Ja ist es der Primärschlüssel – Shawn

+0

ist es möglich, einen int-Basis-Primärschlüssel und Foreign-Schlüssel zu verwenden? – sfossen

Antwort

2

Ah, tut mir leid, ich habe es herausgefunden. Patient.Dosing wurde als Nullen zulassen gesetzt. Ich denke, das hat es zu einer anderen Art von Index gemacht.

0

Versuchen Sie, einen Index für diese Tabelle zu erstellen, und achten Sie darauf, das VARCHAR-Feld in die Liste der Felder aufzunehmen.

+0

lesen Sie die Kommentare, es ist bereits indiziert. – sfossen

2

Für den Rekord, obwohl die Frage beantwortet wird. Normalerweise passieren solche Dinge, weil der Ausführungsplan geändert wird. Vergleichen Sie die Pläne im Abfrageanalysator.

2

Ein anderes Problem sind die Datentypen - wenn p.dosing und l.lookupid differieren - kann beispielsweise nvarchar varchar eine große Auswirkung haben.

Verwandte Themen