加入varchar(50)外键会减慢查询速度

时间:2009-03-02 20:21:05

标签: database tsql optimization

我有这个查询很长,但是为它添加一个where子句,或者连接一个字符串使得运行需要额外的2秒。我无法弄清楚原因。

这是完整的查询:

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

减慢速度的行是:

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

此外,将其移至where子句具有相同的效果:

where p.dosing = 'da_ncd'

否则,查询几乎立即运行。 >.<

4 个答案:

答案 0 :(得分:2)

啊,对不起我弄清楚了。 Patient.Dosing被设置为允许空值。我想这使它成为一种不同的索引。

答案 1 :(得分:2)

记录中,即使问题得到解答。 通常这样的事情会发生,因为执行计划已经改变。比较查询分析器中的计划。

答案 2 :(得分:2)

另一个问题是数据类型 - 如果p.dosing和l.lookupid不同 - 例如,nvarchar与varchar会产生巨大的影响。

答案 3 :(得分:0)

尝试在该表上创建索引,确保在字段列表中正确包含该VARCHAR字段。