优化SQL查询

时间:2010-01-29 12:44:13

标签: sql tsql

我有一个需要1:20分钟执行的sql。它处理一年的数据,但即便如此,我觉得它需要太长时间。我根据另一个查询的建议更改了IN使用EXISTS(在这种情况下,优化不是:S) 你还有其他的优化方法来优化吗?

select gd.descripcion,count(gd.descripcion) as total 
from diagnosticos d,gruposdiagnosticos gd, ServiciosMedicos s, pacientes p,Actos a,historias h 
where p.codigo=h.codpaciente and p.codigo=a.codpaciente and p.codigo=h.codpaciente and p.codigo=s.codpaciente and h.codpaciente=a.codpaciente and h.codpaciente=s.codpaciente and a.codpaciente=s.codpaciente and h.numhistoria=a.numhistoria and h.numhistoria=s.numhistoria and a.numacto=s.numacto and h.codseccion=a.codseccion and a.codseccion=s.codseccion and d.codigo=s.codDiagnostico and gd.codigo=d.codgrupo 
and p.codcompañia ='35' and a.codseccion ='18' 
and (CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) >='20090101') 
and (CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) <='20091231') 
and h.modo ='Urgente' 
and datename(weekday,a.fecatencion)!= 'Sabado' 
and datename(weekday,a.fecatencion)!= 'Domingo' 
AND NOT EXISTS (select * from diasfestivos af where (datename(d,a.fecatencion) + datename(m,a.fecatencion))=(datename(d,af.fechafestiva) + datename(m,af.fechafestiva)) AND CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) >= af.fechafestiva AND CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) < af.fechafestiva + 1 and datepart(yy,af.fechafestiva)='1990') 
AND NOT EXISTS (SELECT * FROM diasfestivos af WHERE CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) >= af.fechafestiva AND CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) < af.fechafestiva + 1 AND datepart(yy,af.fechafestiva)!=1990) 
group by gd.descripcion order by gd.descripcion

使用您的建议更改查询,使其在50秒内完成,谢谢,但应该有一种方法可以减少更多...现在的查询是:

select gd.descripcion,count(gd.descripcion) as total 
from diagnosticos d,gruposdiagnosticos gd, ServiciosMedicos s, pacientes p,Actos a,historias h 
where p.codigo=h.codpaciente and p.codigo=a.codpaciente and p.codigo=h.codpaciente and p.codigo=s.codpaciente and h.codpaciente=a.codpaciente and h.codpaciente=s.codpaciente and a.codpaciente=s.codpaciente and h.numhistoria=a.numhistoria and h.numhistoria=s.numhistoria and a.numacto=s.numacto and h.codseccion=a.codseccion and a.codseccion=s.codseccion and d.codigo=s.codDiagnostico and gd.codigo=d.codgrupo 
and p.codcompañia ='35' and a.codseccion ='18' 
and a.fecAtencion +1 >'20090101'
and a.fecAtencion -1 <'20091231' 
and h.modo ='Urgente'  
and DATEPART(dw,a.fecatencion)!=6 
and DATEPART(dw,a.fecatencion)!=7
AND NOT EXISTS (select * from diasfestivos af where (datename(d,a.fecatencion) + datename(m,a.fecatencion))=(datename(d,af.fechafestiva) + datename(m,af.fechafestiva)) AND a.fecAtencion +1 > af.fechafestiva AND a.fecAtencion -1 < af.fechafestiva and datepart(yy,af.fechafestiva)='1990')
AND NOT EXISTS (SELECT * FROM diasfestivos af WHERE a.fecAtencion +1 > af.fechafestiva AND a.fecAtencion -1 < af.fechafestiva AND datepart(yy,af.fechafestiva)!=1990) 
group by gd.descripcion order by gd.descripcion

我有两个存在的部分因为我有两种类型的节日日期。特别是今年和其他每年适用的人(所以我插入它们像25/12/1990)

最后我发现了这个问题..

其中datename(d,a.fecatencion)+ datename(m,a.fecatencion))=(datename(d,af.fechafestiva)+ datename(m,af.fechafestiva))

有人知道更好的方法吗? (比较tsql省略年份的2个日期时间)

6 个答案:

答案 0 :(得分:6)

  • 使用索引
  • 重写强制转换以使用简单比较between ... and语法
  • 在此datename(weekday,a.fecatencion)!= 'Sabado'
  • 上使用数字比较
  • 你可能会删除Actos a表,并用h.codseccion = '18'替换a.codseccion ='18'
  • 你可能会删除diagnosticos d表,因为我没有看到任何对它的引用
  • 你可能会删除ServiciosMedicos s表,因为我没有看到任何对它的引用
  • 总而言之,我发现你有很多连接,你没有使用所有的表,删除不必要的连接
  • 重写你的最后两个子查询至少要使用union all例如:( select * from)table union all(select * from),那么至少你将有一次运行而不是两次

答案 1 :(得分:1)

如果你必须做所有的演员和地板,那么你的数据库设计是需要的。我坚信数据应该以您需要查询的形式存储。考虑在插入/更新数据时添加列来执行此操作,您可以创建计算字段。然后,每次运行查询时都不必发生这种情况。

答案 2 :(得分:1)

这部分看起来可能是主要问题:

AND NOT EXISTS (
   select * from diasfestivos af 
   where (datename(d,a.fecatencion) + datename(m,a.fecatencion))=
         (datename(d,af.fechafestiva) + datename(m,af.fechafestiva)) 
   AND a.fecAtencion +1 > af.fechafestiva 
   AND a.fecAtencion -1 < af.fechafestiva 
   and datepart(yy,af.fechafestiva)='1990'
 ) 

这看起来基本上是:

AND NOT EXISTS (
   SELECT NULL FROM diasfestivos af 
   WHERE af.fechafestiva BETWEEN '19900101' AND '19910101'
   AND DATEPART(d, a.fecatencion) = DATEPART(d, af.fechafestiva)
   AND DATEPART(m, a.fecatencion) = DATEPART(m, af.fechafestiva)
   AND a.fecatencion != af.fechafestiva 
 )

我一直试图找到一种方法来做同一个日期,但不同的一年,而不必在日期执行多个功能,但我没有设法。

答案 3 :(得分:0)

同时尝试“Sql Server Profiler”。

考虑联接的顺序,以便首先过滤掉大块数据。

答案 4 :(得分:0)

您应该学习如何使用“DateDiff”。查询应使用此构造仅获取2009年的记录:

DATEDIFF(yy, a.fecAtencion, '2009-01-01')

其他一些事情......

首先 - 不要为日期做演员表。

静态日期(例如'2009-01-01')具有隐含的午夜(00:00:00)开始时间。因此,您在开始日期根本不需要演员表,因为2009年的所有内容都大于“2009-01-01”。您也可以使用“2010-01-01”作为结束日期,因为2009年之前(2010年没有任何内容)将在此之前完成。

不使用这些丑陋的强制转换的另一个原因是你可以在SQL查询中指定小时,分钟,秒和msecs,如下所示:'2009-01-01 00:00:00:000'如果你不想要在这个区域留下不明确的查询。

关于使用分析器等的其他建议仍然很好。但我敢打赌你的问题在于你的日期处理。

答案 5 :(得分:0)

以vb.net为例。

我的目标是移除将结果分组/计数到sql server的压力。

尝试这种额外的优化,看看它是否可以缩短执行时间?

strsql="
select gd.descripcion 
from diagnosticos d,gruposdiagnosticos gd, ServiciosMedicos s, pacientes p,Actos a,historias h  
where p.codigo=h.codpaciente and p.codigo=a.codpaciente and p.codigo=h.codpaciente and p.codigo=s.codpaciente and h.codpaciente=a.codpaciente and h.codpaciente=s.codpaciente and a.codpaciente=s.codpaciente and h.numhistoria=a.numhistoria and h.numhistoria=s.numhistoria and a.numacto=s.numacto and h.codseccion=a.codseccion and a.codseccion=s.codseccion and d.codigo=s.codDiagnostico and gd.codigo=d.codgrupo  
and p.codcompañia ='35' and a.codseccion ='18'  
and (CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) >='20090101')  
and (CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) <='20091231')  
and h.modo ='Urgente'  
and datename(weekday,a.fecatencion)!= 'Sabado'  
and datename(weekday,a.fecatencion)!= 'Domingo'  
AND NOT EXISTS (select * from diasfestivos af where (datename(d,a.fecatencion) + datename(m,a.fecatencion))=(datename(d,af.fechafestiva) + datename(m,af.fechafestiva)) AND CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) >= af.fechafestiva AND CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) < af.fechafestiva + 1 and datepart(yy,af.fechafestiva)='1990')  
AND NOT EXISTS (SELECT * FROM diasfestivos af WHERE CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) >= af.fechafestiva AND CAST(FLOOR(CAST(a.fecAtencion AS float)) AS datetime) < af.fechafestiva + 1 AND datepart(yy,af.fechafestiva)!=1990)  
"
cmd = new sqlcommand(strsql, conn)
cmd.commandtimeout = 480
da = new sqldataadapter(cmd)

dt = new datatable
da.fill(dt)

dim dv as new dataview(dt)
dv.sort = "descripcion"

dt2 = dv.totable(true, "descripcion") 'simulate a select distinct from result
dt2.columns.add("total")

for each dr as datarow in dt2.rows
    dr("total") = dt.select("descripcion = '" & dr("descripcion ") & "'").length
next

dt2.acceptchanges()

gridview2.datasource = dt2
gridview2.databind