Оптимизировать SQL-запрос - PullRequest
       13

Оптимизировать SQL-запрос

0 голосов
/ 29 января 2010

У меня есть sql, для выполнения которого требуется 1:20 мин. Он обрабатывает год данных, но я чувствую, что это занимает слишком много времени. Я изменил использование 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

У меня есть 2 части, потому что у меня есть два типа праздничных дат. Те, которые относятся к настоящему году, и другие, которые подаются на каждый год (поэтому я добавляю их как 25/12/1990)

Наконец-то я нашел проблему ... в этой части:

где имя даты (d, a.fecatencion) + имя даты (m, a.fecatencion)) = (имя даты (d, af.fechafestiva) + имя имени (m, af.fechafestiva))

Кто-то знает лучший способ сделать это? (Сравните 2 даты в ЦКЛ без учета года)

Ответы [ 6 ]

6 голосов
/ 29 января 2010
  • Использовать индексы
  • Переписать приведение для использования простого сравнения, вероятно, between ... and Синтаксис
  • Использовать числовое сравнение для этого datename(weekday,a.fecatencion)!= 'Sabado'
  • Вы, вероятно, можете удалить таблицу Actos a и заменить a.codseccion = '18 'на h.codseccion =' 18 '
  • Вы, вероятно, можете удалить таблицу diagnosticos d, так как я не вижу никакой ссылки на нее
  • Вы, вероятно, можете удалить таблицу ServiciosMedicos s, поскольку я не вижу никакой ссылки на нее
  • В общем, я вижу, у вас много объединений, и вы не используете все таблицы, удаляете ненужные объединения
  • Перепишите два последних подзапроса, по крайней мере, для использования union all Например: (выберите * из) Таблица объединения всех (выберите * из), тогда по крайней мере у вас будет один прогон для них, а не два
1 голос
/ 01 февраля 2010

Эта часть выглядит так, как будто это может быть главной проблемой:

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 
 )

Я пытался найти способ сделать вашу ту же дату, но в другой год, без необходимости выполнять несколько функций в даты, но мне не удалось.

1 голос
/ 29 января 2010

Если вам придется делать все, что связано с актерами и актерами, то ваша база данных нуждается в работе. Я твердо верю, что данные должны храниться в той форме, в которой вам нужно их запросить. Рассмотрите возможность добавления столбцов, чтобы сделать это один раз при вставке / обновлении данных, вы можете создавать вычисляемые поля. Тогда это не должно происходить каждый раз, когда вы запускаете запрос.

0 голосов
/ 29 января 2010

на примере 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
0 голосов
/ 29 января 2010

Вы должны научиться использовать «DateDiff». Запрос должен использовать эту конструкцию для получения только записей за 2009 год:

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

Несколько других вещей ...

ПЕРВЫЙ - Не делайте забросы на свидание.

Статические даты (например, «2009-01-01») имеют предполагаемое время начала в полночь (00:00:00). Таким образом, вам вообще не понадобится приведение к дате начала, поскольку в 2009 году все будет больше, чем «2009-01-01». Вы также можете использовать «2010-01-01» в качестве конечной даты, поскольку все в 2009 году (и ничего в 2010 году) будет до этого.

Другая причина не использовать эти уродливые приведения в том, что вы можете указывать часы, минуты, секунды и msecs в SQL-запросе, например, так: '2009-01-01 00: 00: 00: 000', если вы не хотите оставить запрос неоднозначным в этой области.

Другой совет по использованию профилировщика и т. Д. Все еще хорош. Но держу пари, что ваша проблема заключается в том, как вы справляетесь с собеседниками.

0 голосов
/ 29 января 2010

Также попробуйте "Sql Server profiler".

Подумайте о порядке ваших объединений, чтобы сначала отфильтровывались большие куски данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...