簡體   English   中英

優化SQL查詢

[英]Optimize sql query

我有一個需要1:20分鍾執行的SQL。 它處理一年的數據,但是即使如此,我仍感覺花費了太長時間。 我已將EXISTS的IN用法更改為另一個查詢的推薦值(在這種情況下,優化還不夠: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

我有2個存在的部分,因為我有兩種類型的節日日期。 特定於當前年份的年份和其他每年適用的年份(因此,我將其像1990年12月25日這樣插入)

最終,我發現了這一部分的問題。

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

有人知道更好的方法嗎? (比較tsql中省略日期的2個日期時間)

  • 使用索引
  • 重寫強制類型轉換以between ... and語法between ... and使用簡單的比較
  • 在此datename(weekday,a.fecatencion)!= 'Sabado'上使用數字比較datename(weekday,a.fecatencion)!= 'Sabado'
  • 您可能可以刪除Actos a表,並用h.codseccion = '18'替換a.codseccion = '18'
  • 您可能可以刪除diagnosticos d表,因為我沒有看到對它的任何引用
  • 您可能可以刪除ServiciosMedicos s表,因為我看不到任何引用
  • 總而言之,我看到您有很多聯接,並且您不使用所有表,請刪除不必要的聯接
  • 至少重寫最后兩個子查詢以使用union all例如:(select * from)表union all(選擇* from),那么至少您將為它們運行一次,而不是兩次

如果必須執行所有這些工作,那么數據庫設計就需要工作。 我堅信數據應該以查詢的形式存儲。考慮在數據插入/更新后添加列以執行此操作,就可以創建計算字段。 這樣就不必每次運行查詢時都發生。

這部分看起來可能是主要問題:

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 
 )

我一直在嘗試找到一種方法來處理您的日期相同但又不同的年份,而不必在日期上執行多項功能,但是我沒有設法做到。

也嘗試“ SQL Server事件探查器”。

考慮一下連接的順序,以便首先過濾掉大塊數據。

您應該學習如何使用“ DateDiff”。 該查詢應使用此構造來僅獲取2009年的記錄:

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

其他幾件事...

首先-請勿進行約會。

靜態日期(例如“ 2009-01-01”)具有隱含的午夜(00:00:00)開始時間。 因此,從2009年開始,您根本不需要演員表,因為實際上2009年的所有情況都比“ 2009-01-01”大。 您也可以使用“ 2010-01-01”作為結束日期,因為2009年之前的所有日期(2010年沒有)將在此之前。

不使用這些丑陋轉換的另一個原因是,您可以在SQL查詢中指定小時,分鍾,秒和毫秒,例如:'2009-01-01 00:00:00:000',如果您不想離開在該區域的查詢不明確。

關於使用探查器等的其他建議仍然很好。 但是我敢打賭,您的問題出在您的日期處理上。

以vb.net為例。

我的目標是減輕對sql服務器分組/計數結果的壓力。

嘗試這種額外的優化,看看是否可以減少執行時間?

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM