这已经困扰了我大约4个小时,所以我认为是时候寻求帮助了。我在网上找不到类似的东西,但主要是因为价值非常具体,我不确定要找什么......
这是我在Oracle脚本中运行的问题,在SQLPlus 10.2.0.5中运行。
问题:
(名称和实际数据已被更改以保护嫌疑人的身份) 我有一个名为MONKEYS的表和一个名为MONKEY_PUZZLES的表,看起来有点像这样:
MONKEYS
MONKEY_PUZZLES
MONKEY_PUZZLES.GIRAFFE_ID和MONKEYS.GIRAFFE_ID匹配,但每个MONKEY_PUZZLE有一个MONKEYS(因此MONKEY_PUZZLES.GIRAFFE_ID 1可能与MONKEY.MONKEY_ID 1,2和334匹配)。
我想根据MONKEY_PUZZLES.MONKEY_PUZZLE_ID字段设置MONKEYS.MONKEY_PUZZLE_ID字段,因为当前我的MONKEYS.MONKEY_PUZZLE_ID字段为空。我有索引:
我在MONKEYS表中还有超过160万行,在MONKEY_PUZZLES表中有超过50,000行。
我最初使用以下查询:
UPDATE MONKEYS M SET M.MONKEY_PUZZLE_ID =
(SELECT MP.MONKEY_PUZZLE_ID FROM MONKEY_PUZZLES MP
WHERE M.GIRAFFE_ID = MP.GIRAFFE_ID
AND MP.GIRAFFE_ID IS NOT NULL);
然而,这个脚本需要大约2分钟才能从0%到92.67%完成,然后花费超过25分钟才能完成94%。我最终停止了剧本。我运行了几次(我正在使用不同的索引和DBMS_STATS),但每次都会达到92.67%并废弃。
所以我认为一定是我的剧本。我回到原点,吃了一根香蕉,说了很多“Oook”并提出了以下变化脚本,这更加明确:
UPDATE MONKEYS M2 SET M2.MONKEY_PUZZLE_ID =
(SELECT X.MPID FROM
(SELECT M.MONKEY_ID MID, MP.MONKEY_PUZZLE_ID MPID
FROM MONKEYS M INNER JOIN MONKEY_PUZZLES MP
ON MP.GIRAFFE_ID = M.GIRAFFE_ID) X
WHERE X.MID = M2.MONKEY_ID);
然而,这是垃圾。即使使用我的索引,只需要花费超过5分钟就可以达到2%,所以我取消了那个。
然后我想出了以下变化,我非常满意:
UPDATE MONKEYS M SET M.MONKEY_PUZZLE_ID =
(SELECT MP.MONKEY_PUZZLE_ID
FROM MONKEY_PUZZLES MP
WHERE M.GIRAFFE_ID = MP.GIRAFFE_ID
AND EXISTS
(SELECT 1 FROM MONKEY_PUZZLES MP2
WHERE M.GIRAFFE_ID = MP2.GIRAFFE_ID));
然而,我真的不敢相信自己的眼睛,这个剧本几乎与第一个完全相同;在大约2分钟内完成,从0%到92.67%完成,然后绝对年龄再进一步。 92.67%是什么?!
总块数为41,717,所以在它看起来显着减速之前它会达到约38,000个块。
如果您想知道,我在单独的SQLPlus会话中使用以下查询来计算完成的年龄百分比:
SELECT X.*, TO_CHAR(SYSDATE, 'HH24:MI:SS') TIMESTAMP
FROM (select sid, serial#, opname, sofar, totalwork,
round(sofar/totalwork*100,2) "% Complete" from v$session_longops) X
WHERE "% Complete" < 100 and totalwork > 0;
(这是对此的变体:http://searchoracle.techtarget.com/tip/Tracking-the-progress-of-long-running-queries)
请帮助把一只可怜的老虎摆脱苦难!
P.S。我要让脚本一夜之间运行,如果达到100%,我会在早上更新。
编辑:最终只用了57分钟就达到了100%(所以不是那么糟糕),但考虑到它在2分钟内达到了92.67%,那真是太可怕了!答案 0 :(得分:4)
我对您所看到的具体症状没有任何解释 - 可能更新的执行计划有助于解释它 - 但无论如何我希望这会有更好的表现:
MERGE INTO monkeys m
USING monkey_puzzles mp
ON (mp.giraffe_id = m.giraffe_id)
WHEN MATCHED THEN UPDATE SET m.monkey_puzzle_id = mp.monkey_puzzle_id
答案 1 :(得分:1)
如果您遇到类似这样的问题,那么最简单的事情就是完全忽略它。 NB无法解决问题的原因!对于这个查询和你的查询,你应该在monkey_puzzles中有一个关于giraffe_id的索引; Giraffe_id,monkey_puzzle_id会更好。
declare
i number(10) := 0;
begin
for xx in ( select rowid as rid, giraffe_id
from monkeys ) loop
UPDATE MONKEYS M
SET M.MONKEY_PUZZLE_ID = ( SELECT MP.MONKEY_PUZZLE_ID
FROM MONKEY_PUZZLES MP
WHERE MP.GIRAFFE_ID = xx.giraffe_id )
WHERE rowid = xx.rid
;
i := i + 1;
if mod(i,1000) = 0 then
commit;
-- and some show-boating from memory (if you're using PL\SQL)
dbms_application_info.set_module('Updating Monkeys', 'Total: ' || i );
end if;
end loop;
commit;
end;
/