[英]How can I alter my table to make Oracle merge run faster?
I have a table, DASHBOARD, with a primary key of PERSON_ID. 我有一个表,DASHBOARD,主键是PERSON_ID。
I want to populate all PERSON_IDs for each column using a MERGE statement that queries another table for counts, ALERT_EVENTS. 我想使用MERGE语句为每列填充所有PERSON_ID,该语句向另一个表查询计数ALERT_EVENTS。
I have written MERGE statements for each column, below is one of the queries - 我为每一列编写了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);
My problem is this query takes too long to run, usually around 50 minutes. 我的问题是这个查询运行时间太长,通常大约50分钟。
There are 4000 PERSON_IDs in the DASHBOARD table and there are 1.4 million EVENT_IDs in the ALERT_EVENTS table. DASHBOARD表中有4000个PERSON_ID,ALERT_EVENTS表中有140万个EVENT_ID。 The ALERT_EVENTS table is made up of the following columns - 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.
I have tried adding and removing indexes (tried with 1 index and 3 indexes), which doesn't seem to help performance. 我已经尝试添加和删除索引(尝试使用1索引和3个索引),这似乎没有帮助性能。
Based on my EXPLAIN PLAN (below), I believe I have a table structure problem, as my database always wants to do a FULL TABLE SCAN when executing the MERGE statement. 基于我的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
I was going to partition the table, but we only have Oracle Standard, and not Enterprise, so it's not an included feature. 我打算对表进行分区,但我们只有Oracle Standard,而不是Enterprise,因此它不是一个包含的功能。
How can I speed up this merge statement without using partitions? 如何在不使用分区的情况下加速此合并语句?
I am considering throwing out most of the rows, which would help slightly, but the underlying problem still exists. 我正在考虑抛弃大部分行,这会有所帮助,但潜在的问题仍然存在。
What am I missing here? 我在这里错过了什么?
Thanks in advance for any ideas. 提前感谢任何想法。
I've not used merge on Oracle, so not 100% sure this will work, but the following should be faster, especially with an index on alert_events (email_alert_type_id, person_id)
or alert_events (person_id, email_alert_type_id)
. 我没有在Oracle上使用merge,所以不是100%确定这会有效,但以下应该更快,特别是在alert_events (email_alert_type_id, person_id)
或alert_events (person_id, email_alert_type_id)
上有索引。 Ideally you would use the first and see a merge join in the query plan, but I'm not sure if Oracle's query optimizer can do this. 理想情况下,您将使用第一个并在查询计划中查看合并连接,但我不确定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);
I've also included zones in the insert, it's trivial to remove this to stay in line with the original query. 我还在插入中包含了区域,删除它以保持与原始查询一致是微不足道的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.