【问题标题】:Joining on varchar(50) foreign key slows query加入 varchar(50) 外键会减慢查询速度
【发布时间】:2009-03-07 05:04:53
【问题描述】:

我有一个很长的查询,但是向它添加一个 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'

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

【问题讨论】:

  • 是否可以使用int基主键和外键?
  • 在做join时,需要把key加载到内存中,内存是50bytes,int/numeric key只有8..
  • 是的,这就是我在自己编写的应用程序中如何做到这一点,但这种结构是强加给我的。只是想弄清楚发生了什么:
  • l.lookupid 并不重要 - p.dosing 是否已编入索引?
  • 正如一般提示——varchar 连接会比 int 连接更昂贵。如果性能是一个问题,请避免!

标签: database tsql optimization


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-11-22
          • 2011-10-04
          • 1970-01-01
          • 1970-01-01
          • 2015-11-27
          • 2019-08-13
          • 1970-01-01
          相关资源
          最近更新 更多