不同表的复合索引 ORACLE SQL

Composite index on different tables ORACLE SQL

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

  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;   

但是我如何在按列排列的所有顺序上使用索引 (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 DESCrisk_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);  

但这也无济于事( P.S。列 ALERT.RISK, TRANS.AMOUNT , TRANS.DATE_TIME 具有 NULLABLE = true;

我在查询中做了一些修改,并用索引进行了实验。

您查询的变化:

  • 用 ansi 连接替换旧式连接
  • 似乎内部查询计数行可以替换为 not exists... 甚至检查 t1.alert_id is null
  • 添加了解析 row_number 函数而不是 order by 和基于 rownums
  • 的过滤器
  • 我不确定是否需要与 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);