如何使用多个连接和冗余标准优化查询?

时间:2013-03-27 06:59:10

标签: sql sql-server sql-server-2008 tsql

我真的希望你能帮我这个。这是我目前的代码,到目前为止,它是我能做的最好的代码。

 SELECT
      max(t2.pmskey) as pmskey, max(cast(t1.recdate as datetime)) as recdate,
      max(t2.mrtype) as mrtype, max(cast(t1.mrdate as datetime)) as mrdate,
      max(t2.CaseNo) as CaseNo, max(t2.pmclin) as pmclin,
      max(cast(t1.nexteval as datetime)) as nexteval,
      max(cast(t1.repdate as datetime)) as repdate,
      max(t3.mrprocedure) as mrprocedure, max(t2.med_stat) as med_stat,
      max(cast(t1.med_stateff as datetime)) as med_stateff,
      max(t2.clincontact) as clincontact,
      max(cast(t1.datemodf as datetime)) as datemodf, max(t2.modfby) as modfby,
      max(cast(t1.inceptiondate as datetime)) as inceptiondate,
      max(t2.createdby) as createdby, max(cast(t1.date_ent as datetime)) as date_ent,
      max(t2.ppihandler) as ppihandler

 FROM
      tblpms as t1

 JOIN
      (
      select * from tblpms where lower(CaseNo) like '%tr13-011%'

 AND
      cast(mrdate as datetime) IN (select max(cast(mrdate as datetime))
      from tblpms where lower(CaseNo) like '%tr13-011%')
      ) as t2

      on t1.CaseNo COLLATE DATABASE_DEFAULT = t2.CaseNo COLLATE DATABASE_DEFAULT

 JOIN
      (
      select * from tblpms where lower(CaseNo) like '%tr13-011%'

 AND
      lower(mrprocedure) is not null and cast(nexteval as datetime)
      in (select max(cast(nexteval as datetime)) from
      tblpms where lower(CaseNo) like '%tr13-011%')
      ) as t3

      on t1.CaseNo COLLATE DATABASE_DEFAULT = t2.CaseNo COLLATE DATABASE_DEFAULT

      and lower(t2.CaseNo) like '%tr13-011%'

lower(CaseNo)的条件在所有联接中被复制,我不知道如何减少这些条件。我相信有一些事情可以做。如果还有其他可以优化的内容,请将其包含在答案中。

这是我目前基于以下答案的查询。

 SELECT
      max(t2.pmskey) as pmskey, max(cast(t1.recdate as datetime)) as recdate,
      max(t2.mrtype) as mrtype, max(cast(t1.mrdate as datetime)) as mrdate,
      max(t2.CaseNo) as CaseNo, max(t2.pmclin) as pmclin,
      max(cast(t1.nexteval as datetime)) as nexteval,
      max(cast(t1.repdate as datetime)) as repdate,
      max(t3.mrprocedure) as mrprocedure, max(t2.med_stat) as med_stat,
      max(cast(t1.med_stateff as datetime)) as med_stateff,
      max(t2.clincontact) as clincontact,
      max(cast(t1.datemodf as datetime)) as datemodf, max(t2.modfby) as modfby,
      max(cast(t1.inceptiondate as datetime)) as inceptiondate,
      max(t2.createdby) as createdby, max(cast(t1.date_ent as datetime)) as date_ent,
      max(t2.ppihandler) as ppihandler

 FROM
      tblpms as t1

 JOIN
      (
      select * from tblpms where CaseNo = 'TR13-011-CRW'

 AND
      cast(mrdate as datetime) IN (select max(cast(mrdate as datetime))
      from tblpms where CaseNo = 'TR13-011-CRW')
      ) as t2

      on t1.CaseNo COLLATE DATABASE_DEFAULT = t2.CaseNo COLLATE DATABASE_DEFAULT

 JOIN
      (
      select * from tblpms where CaseNo = 'TR13-011-CRW'

 AND
      lower(mrprocedure) is not null and cast(nexteval as datetime)
      in (select max(cast(nexteval as datetime)) from
      tblpms where CaseNo = 'TR13-011-CRW')
      ) as t3

      on t1.CaseNo COLLATE DATABASE_DEFAULT = t2.CaseNo COLLATE DATABASE_DEFAULT

      and CaseNo = 'TR13-011-CRW'

1 个答案:

答案 0 :(得分:3)

与[{1}}匹配时,lower()通常不需要LIKE,因为它case-insensitive by default

此外,当在字符串中间执行搜索(例如LIKE '%whatever%)时,不使用索引。 顺便问一下,你有任何索引吗?您是否尝试过构建查询计划?

正如我所看到的,这个问题的解决方案很少:

  1. Use full text search
  2. 添加另一个索引字段并在查询之前填充一次:

    update tblpms set tr13_flag=1 where CaseNo like '%tr13-011%'

    然后用where lower(CaseNo) like '%tr13-011%'

  3. 替换每个where tr13_flag=1语句
  4. 上述方差:使用索引PERSISTED computed column,因此您可以避免手动计算标记。

  5. 将所有有价值的行抓到临时表中一次:

    选择* 进入#tr13011 来自tblpms,其中较低(CaseNo)喜欢'%tr13-011%'

  6. 并加入它,可能在有趣的字段上添加索引。

    此外,您cast持续:cast(nexteval as datetime)。使用答案中的第4个版本并同时转换为#temp表。

    这种情况对我来说毫无用处:and lower(mrprocedure) is not null and cast(nexteval as datetime)。为什么不简单and mrprocedure is not null

    版本4的示例

    select
        CaseNo,
        mrprocedure,
        cast(mrdate as datetime) as mrdate,
        cast(nexteval as datetime) as nexteval
        -- other required fields from tblpms table
    into #tr13
    from tblpms where CaseNo = 'TR13-011-CRW'
    
    declare @max_mrdate datetime
    declare @max_nexteval datetime
    
    select @max_mrdate=max(mrdate), @max_nexteval=max(nexteval) from #tr13
    
    SELECT
          max(t2.pmskey) as pmskey, max(cast(t1.recdate as datetime)) as recdate,
          max(t2.mrtype) as mrtype, max(cast(t1.mrdate as datetime)) as mrdate,
          max(t2.CaseNo) as CaseNo, max(t2.pmclin) as pmclin,
          max(cast(t1.nexteval as datetime)) as nexteval,
          max(cast(t1.repdate as datetime)) as repdate,
          max(t3.mrprocedure) as mrprocedure, max(t2.med_stat) as med_stat,
          max(cast(t1.med_stateff as datetime)) as med_stateff,
          max(t2.clincontact) as clincontact,
          max(cast(t1.datemodf as datetime)) as datemodf, max(t2.modfby) as modfby,
          max(cast(t1.inceptiondate as datetime)) as inceptiondate,
          max(t2.createdby) as createdby, max(cast(t1.date_ent as datetime)) as date_ent,
          max(t2.ppihandler) as ppihandler
    
     FROM
          tblpms as t1
    
     JOIN
          (
          select * from #tr13 where mrdate = @max_mrdate
          ) as t2
          on t1.CaseNo COLLATE DATABASE_DEFAULT = t2.CaseNo COLLATE DATABASE_DEFAULT
    
     JOIN
          (
          select * from #tr13
            where mrprocedure is not null and nexteval = @max_nexteval
          ) as t3
          on t1.CaseNo COLLATE DATABASE_DEFAULT = t2.CaseNo COLLATE DATABASE_DEFAULT
    
    drop table #tr13
    

    我不确定为什么你需要COLLATE DATABASE_DEFAULT,因为它总是在同一张桌子上。 逻辑对我来说不是很清楚,但似乎产生相同的结果,同时更具可读性(并且可能表现更好):

    select
        CaseNo,
        mrprocedure,
        cast(mrdate as datetime) as mrdate,
        cast(nexteval as datetime) as nexteval,
        pmskey,
        mrtype,
        med_stat,
        clincontact,
        modfby,
        createdby,
        ppihandler
        -- other required fields from tblpms table
    into #tr13
    from tblpms where CaseNo = 'TR13-011-CRW'
    
    declare @max_mrdate datetime
    declare @max_nexteval datetime
    
    select @max_mrdate=max(mrdate), @max_nexteval=max(nexteval) from #tr13
    
    SELECT
          max(t2.pmskey) as pmskey, max(cast(t1.recdate as datetime)) as recdate,
          max(t2.mrtype) as mrtype, max(cast(t1.mrdate as datetime)) as mrdate,
          max(t2.CaseNo) as CaseNo, max(t2.pmclin) as pmclin,
          max(cast(t1.nexteval as datetime)) as nexteval,
          max(cast(t1.repdate as datetime)) as repdate,
          max(t2.mrprocedure) as mrprocedure, max(t2.med_stat) as med_stat,
          max(cast(t1.med_stateff as datetime)) as med_stateff,
          max(t2.clincontact) as clincontact,
          max(cast(t1.datemodf as datetime)) as datemodf, max(t2.modfby) as modfby,
          max(cast(t1.inceptiondate as datetime)) as inceptiondate,
          max(t2.createdby) as createdby, max(cast(t1.date_ent as datetime)) as date_ent,
          max(t2.ppihandler) as ppihandler
    
     FROM tblpms as t1
     JOIN #tr13 t2 on t1.CaseNo = t2.CaseNo
    where
        t2.mrdate = @max_mrdate
        and t2.mrprocedure is not null
        and t2.nexteval = @max_nexteval
    
    drop table #tr13
    

    <强>更新 我们设法将其减少为以下代码:

    declare @max_mrdate datetime
    declare @max_nexteval datetime
    
    select
        @max_mrdate=max(cast(mrdate as datetime)),
        @max_nexteval=max(cast(nexteval as datetime))
    from tblpms
    where CaseNo = 'TR13-011-CRW'
    
    select *
    from tblpms where CaseNo = 'TR13-011-CRW'
    and (
        cast(mrdate as datetime) = @max_mrdate
        or
        (mrprocedure is not null and cast(nexteval as datetime) = @max_nexteval)
    )