需要根据 EXPLAIN PLAN 加快我的 UPDATE QUERY
Need to speed up my UPDATE QUERY based on the EXPLAIN PLAN
我正在使用临时 table 更新我的 table 数据,这需要很长时间,但仍未完成。所以我收集了一个关于查询的解释计划。有人可以建议我如何调整查询或在其上构建索引。
查询:
UPDATE w_product_d A
SET A.CREATED_ON_DT = (SELECT min(B.creation_date)
FROM mtl_system_items_b_temp B
WHERE to_char(B.inventory_item_id) = A.integration_id
and B.organization_id IN ('102'))
where A.CREATED_ON_DT is null;
说明计划:
Plan hash value: 1520882583
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 47998 | 984K| 33M (2)|110:06:25 |
| 1 | UPDATE | W_PRODUCT_D | | | | |
|* 2 | TABLE ACCESS FULL | W_PRODUCT_D | 47998 | 984K| 9454 (1)| 00:01:54 |
| 3 | SORT AGGREGATE | | 1 | 35 | | |
|* 4 | TABLE ACCESS FULL| MTL_SYSTEM_ITEMS_B_TEMP | 1568 | 54880 | 688 (2)| 00:00:09 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("A"."CREATED_ON_DT" IS NULL)
4 - filter("B"."ORGANIZATION_ID"=102 AND TO_CHAR("B"."INVENTORY_ITEM_ID")=:B1)
Note
-----
- dynamic sampling used for this statement (level=2)
对于此查询:
UPDATE w_product_d A
SET A.CREATED_ON_DT = (SELECT min(B.creation_date)
FROM mtl_system_items_b_temp B
WHERE to_char(B.inventory_item_id) = A.integration_id
and B.organization_id IN ('102'))
where A.CREATED_ON_DT is null;
你有问题。为什么要为 inventory_item_id
创建类型错误的临时 table?这可能会减慢任何访问速度。所以,让我们先修复 table,然后再进行更新:
alter table mtl_system_items_b_temp
add better_inventory_item_id varchar2(255); -- or whatever the right type is
update mtl_system_items_b_temp
set better_inventory_item_id = to_char(inventory_item_id);
接下来,让我们定义合适的索引:
create index idx_mtl_system_items_b_temp_3 on mtl_system_items_b_temp(better_inventory_item_id, organization_id, creation_date);
最后,w_product_d
上的索引也有帮助:
create index idx_ w_product_d_1 w_product_d(CREATED_ON_DT);
然后,将查询写为:
UPDATE w_product_d p
SET CREATED_ON_DT = (SELECT min(t.creation_date)
FROM mtl_system_items_b_temp t
WHERE t.better_nventory_item_id) = p.integration_id and
t.organization_id IN ('102')
)
WHERE p.CREATED_ON_DT is null;
尝试 MERGE
语句。它可能会更快,因为它可以一次读取所有 mtl_system_items_b_temp
记录,而不是为 w_product_d
.
中的每一行一遍又一遍地读取它们
此外,您的表看起来像是 Oracle e-BS 环境的一部分。在MTL_SYSTEM_ITEMS_B
这样的环境中,INVENTORY_ITEM_ID
和ORGANIZATION_ID
列是NUMBER
。您似乎在表格中使用了 VARCHAR2
。每当您在查询中不使用正确的数据类型时,就会引起性能问题,因为 Oracle 必须隐式转换为正确的数据类型,并且这样做会失去在列上使用索引的能力。因此,请确保您的查询根据其数据类型正确处理每一列。 (例如,如果列是 NUMBER
,请使用 COLUMN_X = 123
而不是 COLUMN_X = '123'
。
这是 MERGE
示例:
MERGE INTO w_product_d t
USING ( SELECT to_char(inventory_item_id) inventory_item_id_char, min(creation_date) min_creation_date
FROM mtl_system_items_b_temp
WHERE organization_id IN ('102') -- change this to IN (102) if organization_id is a NUMBER field!
) u
ON ( t.integration_id = u.inventory_item_id_char AND t.created_on_dt IS NULL )
WHEN MATCHED THEN UPDATE SET t.created_on_dt = nvl(t.created_on_date, u.min_creation_date) -- NVL is just in case...
我正在使用临时 table 更新我的 table 数据,这需要很长时间,但仍未完成。所以我收集了一个关于查询的解释计划。有人可以建议我如何调整查询或在其上构建索引。
查询:
UPDATE w_product_d A
SET A.CREATED_ON_DT = (SELECT min(B.creation_date)
FROM mtl_system_items_b_temp B
WHERE to_char(B.inventory_item_id) = A.integration_id
and B.organization_id IN ('102'))
where A.CREATED_ON_DT is null;
说明计划:
Plan hash value: 1520882583
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | 47998 | 984K| 33M (2)|110:06:25 |
| 1 | UPDATE | W_PRODUCT_D | | | | |
|* 2 | TABLE ACCESS FULL | W_PRODUCT_D | 47998 | 984K| 9454 (1)| 00:01:54 |
| 3 | SORT AGGREGATE | | 1 | 35 | | |
|* 4 | TABLE ACCESS FULL| MTL_SYSTEM_ITEMS_B_TEMP | 1568 | 54880 | 688 (2)| 00:00:09 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("A"."CREATED_ON_DT" IS NULL)
4 - filter("B"."ORGANIZATION_ID"=102 AND TO_CHAR("B"."INVENTORY_ITEM_ID")=:B1)
Note
-----
- dynamic sampling used for this statement (level=2)
对于此查询:
UPDATE w_product_d A
SET A.CREATED_ON_DT = (SELECT min(B.creation_date)
FROM mtl_system_items_b_temp B
WHERE to_char(B.inventory_item_id) = A.integration_id
and B.organization_id IN ('102'))
where A.CREATED_ON_DT is null;
你有问题。为什么要为 inventory_item_id
创建类型错误的临时 table?这可能会减慢任何访问速度。所以,让我们先修复 table,然后再进行更新:
alter table mtl_system_items_b_temp
add better_inventory_item_id varchar2(255); -- or whatever the right type is
update mtl_system_items_b_temp
set better_inventory_item_id = to_char(inventory_item_id);
接下来,让我们定义合适的索引:
create index idx_mtl_system_items_b_temp_3 on mtl_system_items_b_temp(better_inventory_item_id, organization_id, creation_date);
最后,w_product_d
上的索引也有帮助:
create index idx_ w_product_d_1 w_product_d(CREATED_ON_DT);
然后,将查询写为:
UPDATE w_product_d p
SET CREATED_ON_DT = (SELECT min(t.creation_date)
FROM mtl_system_items_b_temp t
WHERE t.better_nventory_item_id) = p.integration_id and
t.organization_id IN ('102')
)
WHERE p.CREATED_ON_DT is null;
尝试 MERGE
语句。它可能会更快,因为它可以一次读取所有 mtl_system_items_b_temp
记录,而不是为 w_product_d
.
此外,您的表看起来像是 Oracle e-BS 环境的一部分。在MTL_SYSTEM_ITEMS_B
这样的环境中,INVENTORY_ITEM_ID
和ORGANIZATION_ID
列是NUMBER
。您似乎在表格中使用了 VARCHAR2
。每当您在查询中不使用正确的数据类型时,就会引起性能问题,因为 Oracle 必须隐式转换为正确的数据类型,并且这样做会失去在列上使用索引的能力。因此,请确保您的查询根据其数据类型正确处理每一列。 (例如,如果列是 NUMBER
,请使用 COLUMN_X = 123
而不是 COLUMN_X = '123'
。
这是 MERGE
示例:
MERGE INTO w_product_d t
USING ( SELECT to_char(inventory_item_id) inventory_item_id_char, min(creation_date) min_creation_date
FROM mtl_system_items_b_temp
WHERE organization_id IN ('102') -- change this to IN (102) if organization_id is a NUMBER field!
) u
ON ( t.integration_id = u.inventory_item_id_char AND t.created_on_dt IS NULL )
WHEN MATCHED THEN UPDATE SET t.created_on_dt = nvl(t.created_on_date, u.min_creation_date) -- NVL is just in case...