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>
几点可以帮助你优化这个。
- 就像@Stu 指出的那样,
DISTINCT
在 IN()
子句中是不必要的。
where nvl(matched_alert,'N') != 'Y'
不是 sargeable。它将函数应用于列,这会破坏索引的使用。
WHERE column = 'constant'
比 WHERE column <> 'constant'
. 更好地利用索引
- 您可以通过删除子查询来简化逻辑。
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';
以下查询有效并为我提供了预期的结果,但我想对其进行优化。 有没有办法避免子查询,只使用主查询中的条件得到相同的结果:
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>
几点可以帮助你优化这个。
- 就像@Stu 指出的那样,
DISTINCT
在IN()
子句中是不必要的。 where nvl(matched_alert,'N') != 'Y'
不是 sargeable。它将函数应用于列,这会破坏索引的使用。WHERE column = 'constant'
比WHERE column <> 'constant'
. 更好地利用索引
- 您可以通过删除子查询来简化逻辑。
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';