表连接性能不佳

时间:2016-12-13 11:47:55

标签: sql oracle oracle11g sqlperformance

我在Oracle SQL查询中遇到的性能非常差。查询是这样的:

 SELECT distinct idm3.cod
    FROM ibe_partos_m idm3, ibe_padron_prov_2010_m pad2
   WHERE     idm3.codLote = 1
         AND idm3.activo = 1
         AND ((pad2.ar = '2016' and pad2.mes='1') or (pad2.ar = '2015' and pad2.mes='7'))
         AND idm3.cod NOT IN                
           (SELECT idm2.cod
              FROM ibe_partos_m idm2,
                   ibe_padron_prov_2010_m pad
             WHERE     idm2.codLote = 1
                   AND idm2.activo = 1
                   AND ((pad.ar = '2016' and pad.mes='1') or (pad.ar = '2015' and pad.mes='7'))
                   AND pad.tiden != '2'
                   AND idm2.nombreM = pad.NOMB
                   AND idm2.apell1m = pad.APE1
                   AND idm2.apell2m = pad.APE2
                   AND (    idm2.numdocm = pad.IDEN || pad.LIDEN OR 
                                idm2.numdocm = pad.NDOCU OR 
                                idm2.numdocm = pad.LEXTR|| pad.IDEN|| pad.LIDEN OR 
                                idm2.numdocm = pad.LEXTR || '0' || pad.IDEN|| pad.LIDEN OR 
                                idm2.numdocm = pad.lextr || SUBSTR (pad.iden, 2, LENGTH (pad.iden))|| pad.liden)
                )                        
         AND idm3.PROREM = '07'
         AND idm3.nombreM = pad2.nomb
         AND idm3.apell1m = pad2.ape1
         AND idm3.apell2m = pad2.ape2
         AND (   (pad2.tiden = '1' AND pad2.liden IS NOT NULL)
              OR (    pad2.tiden = '3'
                  AND pad2.liden IS NOT NULL
                  AND pad2.lextr IS NOT NULL));

我在表ibe_partos_m,字段codlote和字段cod中定义的索引;在表格ibe_padron_prov_2010_m,字段ape1ape2iden中。所有索引都很简单。

我无法理解为什么我的表现不佳...... ape1ape2中的2个索引是否足以提高联合速度?

提前谢谢!!

编辑:我想要实现的目标是:

  • 让我们将正确的记录定义为内部选择中选择的记录。

  • 我试图获取前一种意义上正确的记录,但仍然适合某些属性,即:

    idm3.codLote = 1
         AND idm3.activo = 1
         AND ((pad2.ar = '2016' and pad2.mes='1') or (pad2.ar = '2015' and pad2.mes='7'))
    
    
    
    AND idm3.PROREM = '07'
         AND idm3.nombreM = pad2.nomb
         AND idm3.apell1m = pad2.ape1
         AND idm3.apell2m = pad2.ape2
         AND (   (pad2.tiden = '1' AND pad2.liden IS NOT NULL)
              OR (    pad2.tiden = '3'
                  AND pad2.liden IS NOT NULL
                  AND pad2.lextr IS NOT NULL));
    

Edit2:正如@Craig Young正确怀疑的那样,我只对获得不同的cod感兴趣(在两个选择中)...但是有一些方法可以告诉数据库服务器停止搜索一旦在某些或两者中找到匹配,给定ibe_partos_m

2 个答案:

答案 0 :(得分:2)

使用JOIN使代码更容易阅读,因为它不言自明。

LEFT JOIN保证从 idm2

返回每一行
  

和adm2.cod为null;

select distinct idm3.cod
  from ibe_partos_m idm3

  inner join ibe_padron_prov_2010_m pad2
     on idm3.nombrem = pad2.nomb
     and idm3.apell1m = pad2.ape1
     and idm3.apell2m = pad2.ape2

  left join (select idm2.cod
          from ibe_partos_m idm2
          inner join ibe_padron_prov_2010_m pad
           on idm2.nombrem = pad.nomb
           and idm2.apell1m = pad.ape1
           and idm2.apell2m = pad.ape2  
         where idm2.codlote = 1
           and idm2.activo = 1
           and ((pad.ar = '2016' and pad.mes = '1') or
               (pad.ar = '2015' and pad.mes = '7'))
           and pad.tiden != '2'         
           and (idm2.numdocm = pad.iden || pad.liden or
               idm2.numdocm = pad.ndocu or
               idm2.numdocm = pad.lextr || pad.iden || pad.liden or
               idm2.numdocm = pad.lextr || '0' || pad.iden || pad.liden or
               idm2.numdocm =
               pad.lextr || substr(pad.iden, 2, length(pad.iden)) ||
               pad.liden))  idm2
   on idm3.cod = idm2.cod   

 where idm3.codlote = 1
   and idm3.activo = 1
   and ((pad2.ar = '2016' and pad2.mes = '1') or
       (pad2.ar = '2015' and pad2.mes = '7'))
   and idm3.prorem = '07'
   and ((pad2.tiden = '1' and pad2.liden is not null) or
       (pad2.tiden = '3' and pad2.liden is not null and
       pad2.lextr is not null))
    and adm2.cod is null;

答案 1 :(得分:2)

警钟在尖叫着:

SELECT distinct idm3.cod

由于查询中存在加入错误,您可能正在使用DISTINCT来隐藏重复项。如果您将其更改为以下内容,您可能会看到您生成大量行仅用于散列重复项:

SELECT COUNT(idm3.cod)

我们不知道您的架构,因此我们无法指出您的错误。但是,您可以从检查每个表的PK字段的适当过滤开始。

我还建议关注Leketo's advice并使用显式JOIN语法。它使加入错误更容易识别。

我也注意到你使用了很多字符串数字。

  • 如果基础字段是char / varchar:您的表设计效率低下。通过将这些列更改为适当的数字类型,可以显着改善它。
  • 如果基础字段已经是数字类型:使用字符串文字过滤器可能会导致不可搜索的查询(即您无法利用索引)。开始使用正确的类型,您可能会看到显着的改进。