不同表ORACLE SQL上的复合索引

时间:2015-02-19 13:27:42

标签: sql oracle indexing

大家好,我需要优化此查询:

  SELECT * 
    FROM 
        (SELECT r.*, ROWNUM RNUM 
        FROM (
            SELECT t0.RISK , t3.AMOUNT, t3.DATE_TIME , t0.ID
            FROM 
                REACTION.ALERT t0, REACTION.INVESTIGATION t1, 
                REACTION.CLASSIFICATION_TYPE t2, REACTION.TRANS t3, 
                REACTION.FRAUD_TYPE t4, REACTION.CARD t5 
            WHERE (
                    (NOT EXISTS (SELECT 1 FROM REACTION.INVESTIGATION WHERE REACTION.INVESTIGATION.ALERT_ID = t0.ID) OR 
                    t1.CLASSIFICATION_TYPE_ID IS NULL OR t2.CLASSIFICATION_TYPE = 2) AND 
                    t0.MODULE_TYPE = 0 AND
                    t0.PROCESSING_MODE_TYPE = 1 AND 
                    t0.ISS_INST IN (1201, 1101)
                ) AND 
                t0.ID = t1.ALERT_ID(+) AND 
                t0.TRANSACTION_ID = t3.ID AND
                t1.CLASSIFICATION_TYPE_ID = t2.ID(+) AND
                t1.FRAUD_TYPE_ID = t4.ID(+) AND
                t3.HPAN = t5.HPAN(+) 
                ORDER BY t0.RISK DESC, t3.AMOUNT DESC, t3.DATE_TIME DESC, t0.ID DESC
            ) r 
        WHERE ROWNUM <= 120)
    WHERE RNUM > 100;   

但是如何在colums上使用所有订单上的索引( t0.RISK DESC,t3.AMOUNT DESC,t3.DATE_TIME DESC,t0.ID DESC )? 我试图创建2个索引:

create index risk_idx on  ALERT (risk,id);
create index amount_date_idx on  TRANS (AMOUNT,DATE_TIME);

但我仍然对TRANS和ALERT表进行全面扫描,但是如果我将排序更改为 ORDER BY t0.RISK DESC,则t0.ID DESC risk_idx 索引有效并且查询执行得更快。 此外,我试图单独为这4列中的每一列设置索引:

create index risk_idx on  ALERT  (risk,1);
    create index amount_idx on  TRANS  (amount,1);  
    create index date_time_idx on  TRANS  (DATE_TIME,1);  

但那也没有帮助( 附:列ALERT.RISK, TRANS.AMOUNT , TRANS.DATE_TIME具有 NULLABLE = true ;

1 个答案:

答案 0 :(得分:0)

我在查询中进行了一些修改,并使用索引进行了扩展。

您的查询中的更改:

  • 用ansi joins替换旧式连接
  • 似乎内部查询计数行可以替换为not exists...,甚至可以检查是否t1.alert_id is null
  • 添加了分析row_number函数而不是order by并基于rownum s过滤
  • 我不确定是否需要与t4和t5连接 - 如果这些表中存在1对多的关系,那么它们是,但是如果一个 那么这些表对结果没有影响(来自t4和。的列) t5不用于条件和顺序)

select r.*
  from (
    select t0.risk , t3.amount, t3.date_time , t0.id, 
        row_number() over (
          order by t0.risk desc, t3.amount desc, t3.date_time desc, t0.id desc) rnum
      from reaction_alert t0
        left join reaction_investigation       t1 on t1.alert_id = t0.id
        left join reaction_classification_type t2 on t2.id = t1.classification_type_id
        join reaction_trans                    t3 on t3.id = t0.transaction_id
        left join reaction_fraud_type          t4 on t4.id = t1.fraud_type_id  
        left join reaction_card                t5 on t5.hpan = t3.hpan         
      where 
        (
          t1.alert_id is null -- <- this should be enough to replace "group by query"
          or t1.classification_type_id is null 
          or t2.classification_type = 2
        ) 
        and t0.module_type = 0 and t0.processing_mode_type = 1
        and t0.iss_inst in (1201, 1101)
    ) r 
  where 100 < rnum and rnum <= 120
  order by rnum

此查询可能需要一些修改,如果没有数据访问,我无法检查一切是否正确。 语法没问题,我在包含查询中提到的列的样本表上运行它。 请检查您的查询和我的查询计数(当然删除rnum上的过滤器)。如果您发现任何逻辑错误,请更正。

<强>索引

没有数据访问很难说,但是连接中使用的列显然是候选者。 您可能在该字段上有索引,但它们似乎是主键或外键。 无论如何,我试试这些:

/* t0 */ create index idx_ra_cmplx1   on reaction_alert (module_type, processing_mode_type, iss_inst);
/* t1 */ create index idx_ri_alert_id on reaction_investigation (alert_id);
/* t2 */ create index idx_rct_id      on reaction_classification_type (id);
/* t3 */ create index idx_rt_id       on reaction_trans (id);
/* t3 */ create index idx_rt_cmplx1   on reaction_trans (id, amount desc, date_time desc);
/* t4 */ create index idx_rft_id      on reaction_fraud_type (id);
/* t5 */ create index idx_rc_hpan     on reaction_card (hpan);

下面是我如何构建表来测试查询。不太重要,但可能对某人有用。

create table reaction_alert (id number, transaction_id number, risk number, module_type number, processing_mode_type number, iss_inst number)
create table reaction_investigation (alert_id number, classification_type_id number, fraud_type_id number);
create table reaction_classification_type (id number, classification_type number);
create table reaction_trans (id number, amount number, hpan number, date_time date);
create table reaction_fraud_type (id number);
create table reaction_card (hpan number);