帮助优化查询

时间:2011-09-16 21:17:46

标签: sql sql-server subquery

我需要优化此查询,请参阅注释行:

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 个答案:

答案 0 :(得分:1)

我要做的是将INNOT 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

答案 1 :(得分:0)

这部分

 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(...)值,这些值在每次插入数据库时​​都会更新。这完全取决于您运行每个查询的频率。

您是否尝试在这些上运行查询优化工具?

答案 2 :(得分:0)

分离子查询,然后进行连接

即。首先查找您在一个查询中排除的所有num_processo。在num_processo字段上执行与processo表的左连接,并排除第一个表的num_processo字段为空的那些

编辑: 表distribuicao和distrib_vincJud之间的关系是什么?

这条线正在扼杀你的表现......

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

子查询中的子查询,然后引用子查询之外的连接表??????