【问题标题】:How can I alter my table to make Oracle merge run faster?如何更改我的表以使 Oracle 合并运行得更快?
【发布时间】:2013-11-09 02:12:18
【问题描述】:

我有一个表 DASHBOARD,其主键为 PERSON_ID。
我想使用 MERGE 语句为每个列填充所有 PERSON_ID,该语句查询另一个表的计数 ALERT_EVENTS。

我已经为每一列写了 MERGE 语句,下面是其中一个查询 -

MERGE INTO DASHBOARD D
USING
    (SELECT PERSON_ID FROM PERSON) P 
ON (D.PERSON_ID = P.PERSON_ID)
WHEN MATCHED THEN
    UPDATE SET D.ZONES = (SELECT COUNT(EVENT_ID) FROM ALERT_EVENTS WHERE PERSON_ID = P.PERSON_ID AND EMAIL_ALERT_TYPE_ID = '40') WHERE D.PERSON_ID = P.PERSON_ID
WHEN NOT MATCHED THEN
    INSERT (D.PERSON_ID)
    VALUES (P.PERSON_ID);

我的问题是这个查询运行时间太长,通常大约 50 分钟。

DASHBOARD 表中有 4000 个 PERSON_ID,ALERT_EVENTS 表中有 140 万个 EVENT_ID。 ALERT_EVENTS 表由以下列组成 -

"EVENT_ID"            NUMBER(*,0) NOT NULL ENABLE,
"PERSON_ID"           NUMBER(*,0) NOT NULL ENABLE,
"DEVICE_ID"              NUMBER(*,0) NOT NULL ENABLE,
"ALERT_TYPE_ID" NUMBER(*,0) NOT NULL ENABLE,
"EVENT_DATE_TIME" DATE NOT NULL ENABLE,
"TEXT"            VARCHAR2(4000 BYTE),
"STATUS"          NUMBER(*,0) DEFAULT 0 NOT NULL ENABLE,
"PROC_STATUS_ID"  NUMBER(*,0) DEFAULT 1 NOT NULL ENABLE,
"ALERT_STATUS_ID" NUMBER DEFAULT 1 NOT NULL ENABLE

and one UNIQUE index on EVENT_ID.

我尝试添加和删除索引(尝试使用 1 个索引和 3 个索引),这似乎对性能没有帮助。

根据我的 EXPLAIN PLAN(如下),我相信我有一个表结构问题,因为我的数据库在执行 MERGE 语句时总是想做一个 FULL TABLE SCAN。

 Operation             Name         Rows    Bytes   Cost (%CPU) Time
 MERGE STATEMENT                4127    314K    21 (5)          00:00:01
 MERGE             DASHBOARD                
 VIEW                   
 HASH JOIN OUTER                4127    120K    21 (5)          00:00:01
 INDEX FAST FULL SCAN  PK_PERSON    4127    16508   4 (0)           00:00:01
 TABLE ACCESS FULL     DASHBOARD    4215    107K    16 (0)          00:00:01
 SORT AGGREGATE                 1   7       
 TABLE ACCESS FULL     ALERT_EVENTS 27  189 5247 (2)    00:01:03

我打算对表进行分区,但我们只有 Oracle 标准版,没有企业版,所以它不是包含的功能。

如何在不使用分区的情况下加快合并语句的速度?

我正在考虑丢弃大部分行,这会有所帮助,但潜在问题仍然存在。

我在这里缺少什么?

提前感谢您的任何想法。

【问题讨论】:

  • 您的查询包含email_alert_type_id,但它不在alert_events 的定义中。对吗?
  • 请看一下这个解决方案:'Handmade Partitioning - a working example for Oracle XE/SE'stackoverflow.com/questions/5801407/…

标签: sql performance oracle merge rdbms


【解决方案1】:

我没有在 Oracle 上使用合并,所以不能 100% 确定这会起作用,但以下应该更快,尤其是在 alert_events (email_alert_type_id, person_id)alert_events (person_id, email_alert_type_id) 上的索引。理想情况下,您会使用第一个并在查询计划中看到合并连接,但我不确定 Oracle 的查询优化器是否可以做到这一点。

merge into 
    dashboard d
using (
    select
        p.person_id,
        count(e.person_id) zones
    from
        person p
            left outer join
        alert_events e
            on p.person_id = e.person_id and 
               e.email_alert_type_id = '40' 
    group by
        p.person_id
    ) x
on
    (d.person_id = x.person_id)
when matched then update
    set d.zones = x.zones
when not matched then insert (person_id, zones)
    values (x.person_id, x.zones);

我还在插入中包含了区域,删除它以保持与原始查询一致是微不足道的。

【讨论】:

  • 我开始将我的查询转换为使用此表单,并且发现速度至少提高了 3 倍,在某些情况下甚至提高了 15 倍。
  • 谢谢!我注意到被合并的行数明显减少,只有那些有值要更新的行,这太棒了。在仔细考虑之后,我意识到我们可能仍然存在这样的情况,即 PERSON 在第 1 次运行中有警报,并且计数在 DASHBOARD 中正确更新 - 但在第 2 次运行中,在警报已解决并从 ALERTS 表中清除后,该 PERSON 的 count 不会更新为 0,因为没有要合并的记录。我可以在没有任何匹配警报的情况下以某种方式将 PERSONS 的 COUNT 更新为 0 吗?
  • @Doyle 我算错了,所以它不会算 0,我现在已经解决了这个问题。如果您要汇总警报表中的多个不同内容,则可以将所有计算汇总到一个查询中。
猜你喜欢
  • 2019-06-13
  • 2017-01-29
  • 1970-01-01
  • 2014-11-28
  • 1970-01-01
  • 2017-03-19
  • 2018-08-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多