【问题标题】:Performance issue while Update remote database from local database从本地数据库更新远程数据库时的性能问题
【发布时间】:2021-08-09 13:15:12
【问题描述】:
  1. 我尝试通过触发器从本地数据库更新远程表(dblink)。 我的成本约为 24990。表数据数接近 3032965。
UPDATE remote_table
SET ip_stats = (
  CASE 
    WHEN :NEW.ip_stats IN (22,30,)  THEN 'Non-Network'
    WHEN :NEW.ip_stats IN (23,31,182)  THEN 'Cancel'
    WHEN :NEW.ip_stats IN (24,32)  THEN 'file'
    WHEN :NEW.ip_stats IN (26,34)  THEN 'online'
    WHEN :NEW.ip_stats IN (63)  THEN 'decrease'
    WHEN :NEW.ip_stats IN (64)  THEN 'increase' 
    END) ,
  ip_comments = (
  CASE :NEW.ip_commts
    WHEN 154 THEN 'increase'
    WHEN 155 THEN 'previous'
    WHEN 156 THEN 'hardware'
    WHEN 157 THEN 'software'
  END) ,
  feedback           = :NEW.feedback ,
  changed_by         = :NEW.changed_by ,
  create_dt          = :NEW.create_dt ,
  status             = 'Y' ,
  sum_amount         = NVL (:NEW.net_amount ,0)
WHERE     ID     = :NEW.new_key;

以下是更新语句的解释计划。

---------------------------------------------------------------------------------------------------
| Id  | Operation              | Name            | Rows  | Bytes | Cost (%CPU)| Time     | Inst   |
---------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT REMOTE|                 |     1 |   195 | 24990   (2)| 00:05:00 |        |
|   1 |  UPDATE                | remote_table    |       |       |            |          | rmt    |
|*  2 |   TABLE ACCESS FULL    | remote_table    |     1 |   195 | 24990   (2)| 00:05:00 | rmt    |
---------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter(TO_NUMBER("A1"."ID")=123478)
 
Note
-----
   - fully remote statement
  1. 此外,当我对该 remote_table 使用 count(*) 时,它的成本与 24990 相同。

注意:我在下面的选择语句中使用INDEX 提示,但它不起作用

SELECT /*+INDEX (a Column_index_name)*/ COUNT(*) FROM remote_table a WHERE a.ID = 123478;

下面是 select count(*) 语句的解释计划。

---------------------------------------------------------------------------------------------------
| Id  | Operation              | Name            | Rows  | Bytes | Cost (%CPU)| Time     | Inst   |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT REMOTE|                 |     1 |     9 | 24990   (2)| 00:05:00 |        |
|   1 |  SORT AGGREGATE        |                 |     1 |     9 |            |          |        |
|*  2 |   TABLE ACCESS FULL    | remote_table    |     1 |     9 | 24990   (2)| 00:05:00 | rmt    |
---------------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter(TO_NUMBER("A1"."ID")=123478)
 
Note
-----
   - fully remote statement

任何人都可以就如何处理这个问题提出建议吗?

【问题讨论】:

  • DB 链接是最糟糕的选择,它们会破坏 oracle 执行计划,让您进行全表扫描。
  • idnew_key的数据类型是什么? id 是字符串吗(这可以解释为什么谓词中有 to_number)?
  • 嗯,除了ID 列是VARCHAR2 @JustinCave 之外,我没有看到任何其他可能性。数字数据类型不会导致隐式转换,DATE 或其他更多exotic 数据类型(如CLOB)将引发ORA-00932: inconsistent datatypes: ...
  • 与您的问题无关,但在触发器中更新远程表通常是个坏主意。这是一个同步更新,因此您通过涉及诸如两阶段提交和额外网络流量之类的事情来减慢本地事务。但更重要的是,您极大地影响了可用性,因为本地系统现在依赖于远程系统的启动和可访问性。有许多专门用于处理复制的技术,几乎肯定比滚动您自己的解决方案更可取。
  • @JustinCave 感谢您的建议和解决方案。

标签: sql oracle performance query-optimization sql-execution-plan


【解决方案1】:

请注意列格式。你的专栏IDVARCAHR2,所以你应该这样查询它。

您的谓词ID = 123478 进行了一个+隐式转换*,它禁止索引访问

使用ID = '123478',它将启用索引访问

带有id varchar2(10)的模拟表示例

 SELECT * FROM tab a WHERE a.ID = 23478;

导致执行计划(为简洁起见)

|*  1 |  TABLE ACCESS FULL| TAB  |  1081 |  2120K| 27171   (1)| 00:00:02 |

   1 - filter(TO_NUMBER("A"."ID")=23478)

但是使用正确格式文字的查询

 SELECT * FROM tab a WHERE a.ID = '23478';

正确的计划

-----------------------------------------------------------------------------------------------
| Id  | Operation                           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |         |     1 |  2009 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TAB     |     1 |  2009 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | TAB_IDX |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("A"."ID"='23478')

【讨论】:

  • 感谢您的回答和解释。我将成本从 24990 大幅降低到 3..!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2011-11-13
相关资源
最近更新 更多