2011-09-16 108 views
2

我需要优化此查询,请参阅comented行:帮助优化查询

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

您正在使用什么RDBMS? [如果MySQL为此避免使用'IN'。](http://stackoverflow.com/q/3417074/73226) –

+1

您希望子查询返回多少行?你是否自己运行子查询并调查结果?除非我错过了显而易见的东西,否则很难在没有关于数据库模式或数据的任何信息的情况下为您提供帮助。 –

+1

为什么优化它?速度?可读性?您的左外连接会杀死您...... –

回答

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 
+0

更改行37 dbj到dvj – celsowm

+0

看起来结果与字面意思相反,它可以以某种方式帮助 – celsowm

+0

如果结果完全相反,则将条件从'IncExc.exclude = 0'更改为'IncExc.exclude = 1' – Xint0

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

你有没有试过在这些上运行你的查询优化器?

+0

取决于RDBMS。据我所知,它们不是相关的子查询。 –

+0

根据他的评论,“WHERE NOT IN(10k lines ...”)'会杀死任何查询的性能。 –

+0

'IN'通常是MySQL中'NOT IN'更大的问题。 –

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 
) 

子查询??????