В oracle, явные курсоры загружают весь результат запроса в память? - PullRequest
0 голосов
/ 10 марта 2010

У меня есть таблица с около 1 миллиарда строк. Я единственный пользователь, поэтому нет никаких разногласий по поводу замков и т. Д. Я заметил, что когда я запускаю что-то вроде этого:

DECLARE   
  CURSOR cur IS SELECT col FROM table where rownum < N; 
BEGIN
  OPEN cur;
  LOOP
    dbms_output.put_line("blah")
  END LOOP;
  CLOSE cur;
END;

существует задержка между моментом, когда я нажимаю ввод, и временем, когда выход начинает поступать. Если N мало, то оно незначительно. Для больших N (или без предложения WHERE) эта задержка составляет порядка часов.

Как вы можете сказать, я новичок в oracle, и я предположил, что курсоры просто сохраняют указатель в таблице, которую они обновляют на каждой итерации цикла. Поэтому я не ожидал отставания, пропорционального размеру таблицы, по которой выполняется итерация. Это неправильно? Загружают ли курсоры весь результат запроса до его итерации?

Есть ли способ перебирать таблицу за строкой без начальных издержек?

Ответы [ 2 ]

9 голосов
/ 10 марта 2010

Что вы видите, так это то, что вывод из DBMS_OUTPUT.PUT_LINE не отображается, пока программа не завершится. Он ничего не говорит о том, как быстро запрос вернул первую строку. (Я предполагаю, что вы намеревались получить данные в вашем примере).

Есть много способов контролировать сеанс, один из них выглядит так:

DECLARE   
  CURSOR cur IS SELECT col FROM table; 
  l_col table.col%ROWTYPE;
BEGIN
  OPEN cur;
  LOOP
    FETCH cur INTO l_col;
    EXIT WHEN cur%NOTFOUND;
    dbms_application_info.set_module('TEST',l_col);
  END LOOP;
  CLOSE cur;
END;

Пока это выполняется, из другого сеанса запустите:

select action from v$session where module='TEST';

Вы увидите, что значение ACTION продолжает изменяться, когда курсор выбирает строки.

0 голосов
/ 18 марта 2010

Мне также нравится отслеживать v $ session_longops для операций, которые оптимизатор Oracle считает «длинными операциями»:

выберите сообщение, time_remaining из v $ session_longops где time_remaining> 0;

...