Это беспокоило меня около 4 часов, поэтому я подумал, что пришло время обратиться за помощью. Я не могу найти ничего похожего в Интернете, но в основном потому, что значения довольно специфичны, и я не совсем уверен, что искать ...
У меня проблема со сценарием Oracle, работающим в SQLPlus 10.2.0.5.
Проблема:
(имена и реальные данные были изменены для защиты личности подозреваемых)
У меня есть таблица с именем MONKEYS и таблица с именем MONKEY_PUZZLES, которая выглядит примерно так:
MONKEYS
- MONKEY_ID
- GIRAFFE_ID
- MONKEY_PUZZLE_ID
MONKEY_PUZZLES
- MONKEY_PUZZLE_ID
- GIRAFFE_ID
MONKEY_PUZZLES.GIRAFFE_ID и MONKEYS.GIRAFFE_ID совпадают, но для MONKEY_PUZZLE существует n MONKEYS (поэтому MONKEY_PUZZLES.GIRAFFE_ID 1 может соответствовать MONKEY.MONKEY_ID 1, 2 и 334).
Я хочу установить поле MONKEYS.MONKEY_PUZZLE_ID на основе поля MONKEY_PUZZLES.MONKEY_PUZZLE_ID, потому что в настоящее время мое поле MONKEYS.MONKEY_PUZZLE_ID равно нулю. У меня есть индексы на:
- MONKEYS.MONKEY_ID (первичный ключ с индексом)
- MONKEYS.GIRAFFE_ID
- MONKEY_PUZZLES.MONKEY_PUZZLE_ID (первичный ключ с индексом)
- MONKEY_PUZZLES.GIRAFFE_ID
У меня также есть более 1,6 миллиона строк в таблице MONKEYS и более 50000 строк в таблице MONKEY_PUZZLES.
Первоначально я использовал следующий запрос:
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% и вылетал.
Так что я подумал, что это мой сценарий. Я вернулся на круги своя, съел банан, много сказал «Оук» и придумал следующий вариантный сценарий, который гораздо более явный:
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%.
РЕДАКТИРОВАТЬ: он достиг 100% в конечном итоге всего через 57 минут (так что не все так плохо), но, учитывая, что он достиг 92,67% за 2 минуты, это довольно ужасно!