При выборе подмножества записей из очень большого набора записей в Oracle не хватает памяти - PullRequest
3 голосов
/ 15 ноября 2010

У меня есть процесс, который конвертирует даты из GMT в восточное стандартное время Австралии.Для этого мне нужно выбрать записи из базы данных, обработать их и затем сохранить их обратно.

Чтобы выбрать записи, у меня есть следующий запрос:

SELECT id,
  user_id,
  event_date,
  event,
  resource_id,
  resource_name
FROM
  (SELECT rowid id,
    rownum r,
    user_id,
    event_date,
    event,
    resource_id,
    resource_name
  FROM user_activity
  ORDER BY rowid)
WHERE r BETWEEN 0 AND 50000

, чтобы выбратьблок из 50000 рядов из ок.60 миллионов строкЯ разделяю их, потому что a) Java (для чего написан процесс обновления) не хватает памяти с слишком большим количеством строк (у меня есть объект bean для каждой строки) и b) у меня есть только 4 гигабайта временного пространства Oracle для воспроизведенияс.

В процессе я использую rowid для обновления записи (поэтому у меня есть уникальное значение) и rownum для выбора блоков.Затем я вызываю этот запрос итерациями, выбирая следующие 50000 записей, пока не останется ни одной (java-программа контролирует это).

Проблема, которую я получаю, заключается в том, что у меня все еще не хватает временного пространства Oracle с этимзапрос.Мой администратор БД сказал мне, что больше временного пространства не может быть предоставлено, поэтому необходимо найти другой метод.

Я попытался заменить подзапрос (который, как я предполагаю, использует все временное пространство с сортировкой) с представлениемно план объяснения с использованием представления идентичен одному из исходных запросов.

Есть ли другой / лучший способ добиться этого, не сталкиваясь с проблемами памяти / пространства?Я предполагаю, что запрос на обновление для обновления дат (в отличие от java-программы) будет страдать от той же проблемы с использованием доступного временного пространства?

Ваша помощь в этом очень важна.

Обновление

Я пошел по пути блока pl / sql, как показано ниже:

declare
  cursor c is select event_date from user_activity for update;
begin
  for t_row in c loop
    update user_activity
      set event_date = t_row.event_date + 10/24 where current of c;
    commit;
  end loop;
end;

Однако у меня заканчивается свободное место.У меня сложилось впечатление, что если коммит был сделан после каждого обновления, то необходимость в отмене места минимальна.Я не прав в этом предположении?

Ответы [ 3 ]

6 голосов
/ 15 ноября 2010

Одно обновление, вероятно, не будет страдать от той же проблемы, и, вероятно, будет на несколько порядков быстрее. Большое количество временных табличных пространств требуется только из-за сортировки. Хотя, если ваш администратор БД так скуп на временное табличное пространство, у вас может закончиться нехватка пространства UNDO или что-то еще. (Посмотрите на ALL_SEGMENTS, насколько велика ваша таблица?)

Но если вы действительно должны использовать этот метод, возможно, вы можете использовать фильтр вместо заказа по. Создайте 1200 ведер и обработайте их по одному:

where ora_hash(rowid, 1200) = 1
where ora_hash(rowid, 1200) = 2
...

Но это будет ужасно, ужасно медленно. И что произойдет, если значение изменяется в середине процесса? Один оператор SQL - почти наверняка лучший способ сделать это.

0 голосов
/ 16 ноября 2010

Как насчет того, чтобы вообще не обновлять его?

rename user_activity to user_activity_gmt

create view user_activity as
select id,
  user_id,
  event_date+10/24 as event_date,
  event,
  resource_id,
  resource_name
from user_activity_gmt;
0 голосов
/ 15 ноября 2010

Почему бы не одно обновление или слияние?Или вы можете написать анонимный блок pl / sql с обработкой данных с помощью курсора. Например

declare
  cursor c is select * from aa for update;
begin
  for t_row in c loop
    update aa
     set val=t_row.val||' new value';
  end loop;
  commit;
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...