【问题标题】:Need to speed up my UPDATE QUERY based on the EXPLAIN PLAN需要根据解释计划加快我的更新查询
【发布时间】:2016-03-25 06:46:53
【问题描述】:

我正在使用临时表更新我的表数据,这需要很长时间,但仍未完成。所以我收集了一个关于查询的解释计划。有人可以建议我如何调整查询或在其上构建索引。

查询:

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)

【问题讨论】:

  • 如果我是你,我会考虑在 (integration_id, created_on_dt) 的 w_product_d 上添加一个索引。并且可能是 (to_char(inventory_item_id)) 的 mtl_system_items_b_temp 上基于函数的索引
  • 我看到这种更新如果改成对应的MERGE语句会快很多

标签: sql oracle indexing sql-execution-plan


【解决方案1】:

对于这个查询:

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 创建一个类型错误的临时表?这可能会减慢任何访问速度。所以,让我们先修复表,然后进行更新:

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;

【讨论】:

  • 不会忽略 created_on_dt 上的索引,因为您正在检查 created_on_dt is null,并且空值将永远不会存储在该索引中?这就是为什么我建议在 (integration_id, created_on_dt) 上建立索引。
  • 太棒了!我错过了 to_char 转换。我从来不知道这会导致开销。我正在添加更新的解释和查询。你认为更新查询可以改进吗,因为它仍然预计在 40 分钟。:
  • @Boneist 你想让我在 TEMP 表上创建所有这三个索引:better_inventory_item_id、organization_id、creation_date 吗?和 CREATED_ON_DT 上的 IGNORE 索引?
  • 继续使用临时表上的索引,但关于 w_product_d 表上的索引,我会确保在索引中包含第二列以及 created_on_dt。如果不这样做,那么您的 null created_on_dts 将不会存储在索引中(因为如果普通 btree 索引中的所有列都为 null,则该行不会存储在索引中)。根据使用 w_product_d 表的其他查询,在 (integration_id, created_on_dt) 上创建索引可能有意义,或者如果索引在 (created_on_dt, integration_id) 上,您可能会看到此查询的改进
  • @Boneist 使用组合(created_on_dt, integration_id)在 w_product_d 表上创建索引后更新过程的解释计划是 00:38:00。这是我能做到的最好的,还是有什么不能做的?从110:06:25到00:38:28真的进步很大!!!
【解决方案2】:

尝试使用MERGE 语句。它可能会更快,因为它可以一次读取所有mtl_system_items_b_temp 记录,而不是为w_product_d 中的每一行一遍又一遍地读取它们。

此外,您的表看起来像是 Oracle e-BS 环境的一部分。在MTL_SYSTEM_ITEMS_B 这样的环境中,INVENTORY_ITEM_IDORGANIZATION_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...

【讨论】:

  • 谢谢麦克皮克。我会遵守的!
  • 仅当为 Oracle 定义了足够的约束以确保 w_product_d 在该隐式视图中保留键。
猜你喜欢
  • 1970-01-01
  • 2019-07-04
  • 2011-02-16
  • 2010-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-09
  • 1970-01-01
相关资源
最近更新 更多