INNER JOIN查询

时间:2017-02-10 07:25:21

标签: mysql sql optimization

我在优化(应该是)简单的SQL查询时遇到了问题但是时间问题严重。我已经写了三遍,但没有一个能奏效。这是我希望工作的原始版本:

SELECT RSKADDR.*
FROM EDW_BASE.RCI_RISK_ADDRESS RSKADDR
INNER JOIN (
  SELECT DISTINCT COVER_RISK_ID
  FROM  EDW_BASE.RCI_COVER_RISK_MASTER RSKMASTER
  INNER JOIN 
  (SELECT DISTINCT CONTACT_ID, FOLLOW_UP_DATE 
  FROM EDW_STG.STG_CIM_SVOM03
  WHERE OUTSTANDING = 1 AND QUEUE = 'CIM Update for Contact Address') ADDR_WF
  ON RSKMASTER.CONTACT_CODE = ADDR_WF.CONTACT_ID
  WHERE RSKMASTER.IS_STORNO != 1 
        AND RSKMASTER.PRODUCT_CODE = 'HOME' 
        AND  ADDR_WF.FOLLOW_UP_DATE >= RSKMASTER.COVER_EFF_START_DATE 
        AND RSKMASTER.POLICY_STATUS_CODE = 'POLICY'
        AND ADDR_WF.FOLLOW_UP_DATE <= RSKMASTER.COVER_EFF_END_DATE 
  ) ACTVRSK
ON ACTVRSK.COVER_RISK_ID = RSKADDR.RISK_ID

第一个内部联接中的代码一直运行到最后。也就是说,第二个SELECT查询(在第一个和主要SELECT查询的INNER JOIN查询中)可以快速运行而不会出现问题。当我在主SELECT查询的INNER JOIN中集成第二个SELECT查询时出现问题(选择RSKADDR。*)

然后似乎执行永无止境!

我尝试了其他方法和相同的结果:

SELECT RSKADDR.*
FROM EDW_BASE.RCI_RISK_ADDRESS RSKADDR

INNER JOIN EDW_BASE.RCI_COVER_RISK_MASTER RSKMASTER
ON RSKMASTER.COVER_RISK_ID = RSKADDR.RISK_ID
   AND RSKMASTER.IS_STORNO != 1 
   AND RSKMASTER.PRODUCT_CODE = 'HOME' 
   AND RSKMASTER.POLICY_STATUS_CODE = 'POLICY'

INNER JOIN EDW_STG.STG_CIM_SVOM03 ADDR_WF
ON OUTSTANDING = 1 AND QUEUE = 'CIM Update for Contact Address'
   AND RSKMASTER.CONTACT_CODE = ADDR_WF.CONTACT_ID
   AND ADDR_WF.FOLLOW_UP_DATE >= RSKMASTER.COVER_EFF_START_DATE
   AND ADDR_WF.FOLLOW_UP_DATE <= RSKMASTER.COVER_EFF_END_DATE  

这很荒谬。这是一个如此简单的查询,无法让它发挥作用。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

DISTINCT是一项代价高昂的操作,很少需要。它通常表示数据库设计错误或查询写得不好。在你的查询中,你甚至反复这样做;看起来不太好。

第二个查询看起来好多了。正如你所说,你得到了相同的结果,第一个查询中的DISTINCT显然是多余的

我看到你在做连接,但你选择的只是一个表中的数据。那么为什么要加入呢?从您想要数据的表中选择,并将您的标准放在WHERE所属的位置。

以下查询可能更快,因为它清楚地表明我们只是在检查是否在其他表中找到匹配项。但是,MySQL以IN子句表现不佳而闻名,因此可能取决于您使用的版本。

select *
from edw_base.rci_risk_address
where risk_id in
(
  select rm.cover_risk_id
  from edw_base.rci_cover_risk_master rm
  where rm.is_storno <> 1 
    and rm.product_code = 'HOME' 
    and rm.policy_status_code = 'POLICY'
    and exists
    (
      select * 
      from edw_stg.stg_cim_svom03 adr 
      where adr.contact_id      = rm.contact_code
        and adr.follow_up_date >= rm.cover_eff_start_date
        and adr.follow_up_date <= rm.cover_eff_end_date 
        and adr.outstanding = 1
        and adr.queue = 'CIM Update for Contact Address'
    )
);

无论如何,根据您的第二个查询或我的第二个查询,我认为以下索引会有所帮助:

create index idx1 on rci_cover_risk_master
(
   product_code, 
   policy_status_code, 
   is_storno, 
   contact_code, 
   cover_eff_start_date, 
   cover_eff_end_date, 
   cover_risk_id
);

create index idx2 on stg_cim_svom03
(
  contact_id, 
  follow_up_date, 
  outstanding, 
  queue
);

create index idx3 on rci_risk_address(risk_id);

答案 1 :(得分:0)

从查询中,您只需要RSKADDR个数据,因此无需INNER JOIN。您可以使用EXISTS关键字执行相同操作。请尝试以下查询

SELECT RSKADDR.*
FROM EDW_BASE.RCI_RISK_ADDRESS RSKADDR
WHERE EXISTS (
  SELECT 1
  FROM  EDW_BASE.RCI_COVER_RISK_MASTER RSKMASTER
  WHERE EXISTS 
  (SELECT 1 
  FROM EDW_STG.STG_CIM_SVOM03
  WHERE OUTSTANDING = 1 AND QUEUE = 'CIM Update for Contact Address') ADDR_WF
  AND RSKMASTER.CONTACT_CODE = ADDR_WF.CONTACT_ID
  AND RSKMASTER.IS_STORNO != 1 
        AND RSKMASTER.PRODUCT_CODE = 'HOME' 
        AND  ADDR_WF.FOLLOW_UP_DATE >= RSKMASTER.COVER_EFF_START_DATE 
        AND RSKMASTER.POLICY_STATUS_CODE = 'POLICY'
        AND ADDR_WF.FOLLOW_UP_DATE <= RSKMASTER.COVER_EFF_END_DATE 
  ) 
AND RSKMASTER.COVER_RISK_ID = RSKADDR.RISK_ID
)

注意:我没有测试查询,因为没有可用的模式。