Помогите оптимизировать запрос - PullRequest
2 голосов
/ 17 сентября 2011

Мне нужно оптимизировать этот запрос, см. Прокомментированную строку:

SELECT p.NUM_PROCESSO,
       p.NUM_PROC_JUD,
       p.Num_Proc_Jud_Antigo1,
       p.Num_Proc_Jud_Antigo2,
       p.Num_Proc_Jud_Novo,
       a.assunto,
       su.subassunto,
       u.UNIDADE,
       s.SERVIDOR,
       dvj.data_vinc,
       p.TIPO,
       c.DESC_CLASSIF
FROM   processo p
       LEFT OUTER JOIN assunto a
         ON a.cod_assunto = p.cod_assunto
       LEFT OUTER JOIN subassunto su
         ON su.cod_subassunto = p.cod_subassunto
       LEFT OUTER JOIN Distrib_VincJud dvj
         ON dvj.num_processo = p.num_processo
       LEFT OUTER JOIN servidor s
         ON S.COD_SERVIDOR = dvj.COD_SERVIDOR
       LEFT OUTER JOIN unidade u
         ON u.COD_UNIDADE = s.COD_UNIDADE
       LEFT OUTER JOIN Classif_Processo c
         ON C.COD_CLASSIF = p.COD_CLASSIF
WHERE  p.TIPO = 'J'
       AND p.NUM_PROCESSO NOT IN (SELECT d.num_processo
                                  FROM   distribuicao d
                                  WHERE  d.COD_SERVIDOR in ( '0', '000' )
                                         AND d.num_distribuicao IN
                                             (SELECT MAX(num_distribuicao)
                                              FROM   Distribuicao
                                              GROUP  BY num_processo)
                                         --this suquery return 100k lines !!! and consume all CPU:
                                         AND dvj.id_vinc IN
                                                (SELECT MAX(id_vinc)
                                                FROM Distrib_VincJud
                                                where  ativo = '1'
                                                GROUP  BY num_processo))
       AND p.NUM_PROCESSO NOT IN (SELECT num_processo
                                  FROM   Anexos)
       AND s.ATIVO = 1  

Мое ужасное решение на данный момент: http://pastebin.com/C4PHNsSc

Ответы [ 3 ]

1 голос
/ 17 сентября 2011

Что бы я сделал, это конвертировал IN и NOT IN в объединения:

SELECT p.NUM_PROCESSO, p.NUM_PROC_JUD, p.Num_Proc_Jud_Antigo1,
    p.Num_Proc_Jud_Antigo2, p.Num_Proc_Jud_Novo, a.assunto,
    su.subassunto, u.UNIDADE, s.SERVIDOR, dvj.data_vinc, p.TIPO,
    c.DESC_CLASSIF
FROM
    processo p
    INNER JOIN (
        SELECT p.num_processo,
            CASE WHEN dvj.id_vinc IS NOT NULL
                AND d.num_distribuicao IS NOT NULL
                OR a.num_processo IS NOT NULL THEN
                1
            ELSE
                0
            END exclude
        FROM
            processo p
            LEFT JOIN Anexos a
                ON p.num_processo = a.num_processo
            LEFT JOIN (
                SELECT num_processo,
                    MAX(num_distribuicao) AS max_distribuicao
                FROM Distribuicao
                GROUP BY num_processo
            ) md ON p.num_processo = md.num_processo
            LEFT JOIN (
                SELECT num_processo, MAX(id_vinc) AS max_vinc
                FROM Distrib_VincJud
                WHERE ativo = '1'
                GROUP BY num_processo
            ) mv on p.num_processo = mv.num_processo
            LEFT JOIN distribuicao d
                ON p.num_processo = d.num_processo
                    AND md.max_distribuicao = d.num_distribuicao
            LEFT JOIN Distrib_VincJud dvj
                ON p.num_processo = dvj.num_processo
                    AND mv.max_vinc = dvj.id_vinc
        WHERE d.COD_SERVIDOR in ('0', '000')
    ) IncExc
        ON p.num_processo = IncExc.num_processo
    LEFT OUTER JOIN assunto a
        ON a.cod_assunto = p.cod_assunto
    LEFT OUTER JOIN subassunto su
        ON su.cod_subassunto = p.cod_subassunto
    LEFT OUTER JOIN Distrib_VincJud dvj
        ON dvj.num_processo = p.num_processo
    LEFT OUTER JOIN servidor s
        ON S.COD_SERVIDOR = dvj.COD_SERVIDOR
    LEFT OUTER JOIN unidade u
        ON u.COD_UNIDADE = s.COD_UNIDADE
    LEFT OUTER JOIN Classif_Processo c
        ON C.COD_CLASSIF = p.COD_CLASSIF
WHERE
    p.TIPO = 'J'
    AND IncExc.exclude = 0
    AND s.ATIVO = 1
0 голосов
/ 17 сентября 2011

Отделите подзапросы, а затем выполните объединение

т.е. сначала найдите все num_processo, которые вы исключаете из одного запроса. выполните левое соединение с таблицей процесса в поле num_processo и исключите те, в которых поле num_processo первой таблицы имеет значение null

Edit: Какова взаимосвязь между таблицами distribicao и distrib_vincJud?

эта строка убивает ваше выступление ...

AND dvj.id_vinc IN
(   SELECT MAX(id_vinc)
    FROM Distrib_VincJud
    where  ativo = '1'
    GROUP  BY num_processo
)

подзапрос в подзапросе, который затем ссылается на объединенную таблицу вне подзапроса ??????

0 голосов
/ 17 сентября 2011

Эта часть

 AND p.NUM_PROCESSO NOT IN (

        SELECT d.num_processo FROM distribuicao d 
        WHERE d.COD_SERVIDOR in ('0','000') 
        AND d.num_distribuicao IN (
              SELECT MAX(num_distribuicao) FROM Distribuicao GROUP BY num_processo
        )

и эта часть

  AND p.NUM_PROCESSO NOT IN (

        SELECT num_processo FROM Anexos

  )

будут самыми большими узкими местами в запросе, поскольку у вас есть вложенные подзапросы.

У вас также есть несколько из них:

SELECT MAX(id_vinc) FROM Distrib_VincJud where ativo = '1' GROUP BY num_processo)
SELECT MAX(num_distribuicao) FROM Distribuicao GROUP BY num_processo

Вы можете получить еще несколько секунд, если разрешить этим отдельным запросам сохранять результаты.

На самом деле, вам лучше иметь отдельную таблицу с этими значениями NOT IN (...), которая обновляется при каждой вставке в вашу базу данных. Все зависит от того, как часто вы выполняете каждый запрос.

Вы пытались запустить Оптимизатор запросов на них?

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