提问人:user1402648 提问时间:6/24/2023 最后编辑:SelVaziuser1402648 更新时间:6/26/2023 访问量:141
“IS NULL”的 Oracle SQL 性能问题 - NVL
Oracle SQL Performance issue with 'IS NULL' - NVL
问:
我使用的是 Oracle 12.2 版本。我有 SQL 有两个过滤条件来从大表中获取 NULL 值。我已将其转换为 和 .IS NULL
NVL (OFF_CODE, -1)=-1
nvl(off_date,'01-JAN-1900')= '01-JAN-1900'
我在两列上创建了基于功能的复合索引,然后我采用了粘贴到此处的解释计划。COST 从 800 万降低到现在的 122。
看到这个计划后,我非常高兴。但 SQL 会持续运行几分钟。在更改之前,它在 15 分钟内做出响应。即使成本降低,响应速度也不快,可能是什么问题?如何更换 IS NULL 以获得更好的性能?
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 192 | 122 (1)| 00:00:01 |
| 1 | HASH GROUP BY | | 4 | 192 | 122 (1)| 00:00:01 |
| 2 | NESTED LOOPS | | 146 | 7008 | 121 (0)| 00:00:01 |
| 3 | NESTED LOOPS | | 148 | 7008 | 121 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID BATCHED| TABLE_NAME1 | 4 | 128 | 8 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | INDEX_TABLE_NAME1 | 4 | | 4 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | INDEX_TABLE_NAME2 | 37 | | 3 (0)| 00:00:01 |
| 7 | TABLE ACCESS BY INDEX ROWID | TABLE_NAME2 | 37 | 592 | 36 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access(NVL("OFF_CODE_ID",(-1))=(-1) AND NVL("OFF_DATE",'01-JAN-1900')='01-JAN-1900')
6 - access("I"."ITEM_ID"="IGP"."ITEM_ID")
我的查询
SELECT /*+ index (i, INDEX_TABLE_NAME1) */
i.item_id,
SUM(coalesce(igp. DEPR_cost, 0) + coalesce(igp.act_dprctn_cost, 0)) depr_cost
FROM
TABLE_NAME1 i,
TABLE_NAME2 igp
WHERE 1 = 1
AND i.Item_id = igp.item_id
AND nvl(i.off_code_id,-1) = -1
AND nvl(i.off_date,'01-JAN-1900') = '01-JAN-1900'
GROUP BY i.item_id;<br/>
我的索引:
create index INDEX_TABLE_NAME1 on TABLE_NAME1( nvl( off_code_id,-1),nvl( off_date,'01-JAN-1900'));
答:
1赞
The Impaler
6/24/2023
#1
如果表列上的空值百分比低于 5%,则可以促进索引的使用。如果是这种情况,则可以使用第二个表作为驱动表,并将查询编写为:
select
u.item_id,
sum(coalesce(u.depr_cost, 0) + coalesce(u.act_dprctn_cost, 0)) as depr_cost
from table_name1 t
join table_name2 u on u.item_id = t.item_id
where u.off_code is null
and u.off_date is null
group by u.item_id
此查询将受益于以下索引:
create index ix1 on table_name2 (item_id, off_code, off_date);
create index ix2 on table_name1 (item_id); -- probably already exists
顺便说一句,我无法理解查询使用表 #1 的用途,因为所有值都来自表 #2。只是想知道......
1赞
deroby
6/26/2023
#2
我的印象是,您只对这两个字段为 NULL 的记录感兴趣。您是否有其他查询来筛选这些列以查找实际值?如果没有,为什么不创建一个筛选索引呢?
CREATE INDEX INDEX_TABLE_NAME1_NULL_NULL on TABLE_NAME1( i.item_id) WHERE (off_code_id IS NULL AND off_date IS NULL);
然后将 SQL 改回
SELECT /*+ index (i, INDEX_TABLE_NAME1) */
i.item_id,
SUM(coalesce(igp. DEPR_cost, 0) + coalesce(igp.act_dprctn_cost, 0)) depr_cost
FROM
TABLE_NAME1 i,
TABLE_NAME2 igp
WHERE 1 = 1
AND i.Item_id = igp.item_id
AND i.off_code_id IS NULL
AND i.off_date IS NULL
GROUP BY i.item_id;
笔记:
- 这也避免了意外地包括具有实际值和这些字段中的记录
-1
1 jan 1900
- 尝试使用结构而不是您现在拥有的结构,我怀疑它会对执行计划产生任何影响,但它只是可读性更好,因此恕我直言,不易出错。
JOIN .. ON
下一个:Oracle:与 NULL 连接
评论