SQL 通过替换子查询优化查询

SQL query optimisation by replacing subquery

以下查询有效并为我提供了预期的结果,但我想对其进行优化。 有没有办法避免子查询,只使用主查询中的条件得到相同的结果:

select  trim(count(tc_grp_id)) 
from FRD_RULES_TIME 
where tc_grp_id NOT IN 
    (SELECT DISTINCT tc_grp_id 
     from FRD_RULES_TIME 
     where nvl(matched_alert,'N') != 'Y' 
     and tc_grp_id  like 'N%');

PS: 在PLSQL中,NVL函数让我们在遇到空值时替换一个值

感谢任何意见

将该查询(使用 NOT IN!=)恢复到其 更简单的 版本可能如下所示:

SELECT COUNT (*)
  FROM frd_rules_time
 WHERE    NVL (matched_alert, 'N') = 'Y'
       OR tc_grp_id NOT LIKE 'N%';

count函数的修剪结果没有用)


为什么?因为这就是您的查询(使用我的示例数据)returns:

SQL> WITH
  2     frd_rules_time (tc_grp_id, matched_alert)
  3     AS
  4        (SELECT 'ABC', 'Y' FROM DUAL
  5         UNION ALL
  6         SELECT 'NXY', 'N' FROM DUAL
  7         UNION ALL
  8         SELECT 'NBA', NULL FROM DUAL
  9         UNION ALL
 10         SELECT 'NDD', 'Y' FROM DUAL
 11         UNION ALL
 12         SELECT 'CZY', 'N' FROM DUAL)
 13    SELECT *
 14      FROM FRD_RULES_TIME
 15     WHERE tc_grp_id NOT IN (SELECT DISTINCT tc_grp_id
 16                               FROM FRD_RULES_TIME
 17                              WHERE     NVL (matched_alert, 'N') != 'Y'
 18                                    AND tc_grp_id LIKE 'N%')
 19  ORDER BY tc_grp_id;

TC_GRP_ID  MATCHED_ALERT
---------- ---------------
ABC        Y
CZY        N
NDD        Y

SQL>

而“我的”查询 returns 相同:

 <snip>
 13    SELECT *
 14      FROM frd_rules_time
 15     WHERE    NVL (matched_alert, 'N') = 'Y'
 16           OR tc_grp_id NOT LIKE 'N%'
 17  ORDER BY tc_grp_id;

TC_GRP_ID  MATCHED_ALERT
---------- ---------------
ABC        Y
CZY        N
NDD        Y

SQL>

几点可以帮助你优化这个。

  1. 就像@Stu 指出的那样,DISTINCTIN() 子句中是不必要的。
  2. where nvl(matched_alert,'N') != 'Y' 不是 sargeable。它将函数应用于列,这会破坏索引的使用。
  3. WHERE column = 'constant'WHERE column <> 'constant'.
  4. 更好地利用索引
  5. 您可以通过删除子查询来简化逻辑。
  6. TRIM(number) 没有用,除非您 必须 将数字输出为文本字符串。

应用查询的这些原则。

select  count(tc_grp_id) 
from FRD_RULES_TIME 
where (matched_alert IS NULL OR matched_alert = 'N')
  and tc_grp_id LIKE 'N%';

如果还是太慢,你可以创建一个covering index来加速它。

CREATE INDEX match_grp ON FRD_RULES_TIME (matched_alert, tc_grp_id);

如果您在 MATCHED_ALERT 或 TC_GRP_ID 上没有索引,另一种选择:

SELECT COUNT(TC_GRP_ID)
  FROM FRD_RULES_TIME
 WHERE NVL(MATCHED_ALERT, 'N') = 'Y'
   AND SUBSTR(NVL(TC_GRP_ID, 'X'), 0, 1) <> 'N';