Dsvolk > > Oracle > > Faq > > Cursors My Blog | Search | About
(Not Logged In)
[ welcome! ] [ news ] [ install ] [ jump-jet ] [ app ] [ rac ] [ papers ] [ dba ] [ dvp ] [ racdd4d ] [ oem ] [ statspack ] [ education ] [ tuning ] [ ias ] [ backup ] [ dataprotection ] [ security ] [ oid ] [ options ] [ integration ] [ sales ] [ sun ] [ linux ] [ consulting ] [ faq ]

Cursors Faq

Соглашение о материалах на этом сайте

Мой oracle blog
true dsvolk!
О бедных курсорах замолвите слово  
Во время извлечения записей мы часто не задумываемся о том, что на самом деле происходит за нашим кодом, пока, скажем Oracle не призовет нас к ответу высказав нам свое "maximum open cursor exceeded". Так давайте посмотрим что это и как работает:

Вообще курсоры  бывают 2 типа:

  • implicit - подразумеваемый, не выраженный явно, скрытый (translated by yandex lingvo)
  • explicit - искренний, откровенный, открытый, прямой

Пример первого типа : 

declare

x varchar2(100);

begin 

select fullname into 'x' from emp where id = 10023;

end;

Пример второго:

declare

c cursor is select fullname from emp;

begin 

open c;

for 1....10000 loop

fetch c into c.rec ;

end loop;

close c;

end;

 

Что использовать в обычной жизни ? Благодаря Tom Kyte мы знаем теперь что неявные курсоры быстрее и лучше. Вот код который он использовал для тестирования:

Неявный курсор:

declare
l_dummy dual.dummy%type;
l_start number default dbms_utility.get_time;
begin
for i in 1 .. 10000
loop
select dummy into l_dummy from dual;
end loop;
dbms_output.put_line
( 'Elapsed ' || round( (dbms_utility.get_time-l_start)/100, 2 ) );
end;
/

Elapsed 1.98

И напротив, с явным курсором:

declare
cursor c1 is select * from dual;
l_dummy dual.dummy%type;
l_start number default dbms_utility.get_time;
begin
for i in 1 .. 10000
loop
open c1;
fetch c1 into l_dummy;
close c1;
end loop;
dbms_output.put_line
( 'Elapsed ' || round( (dbms_utility.get_time-l_start)/100, 2 ) );
end;
/

Elapsed 2.55

Видно что явные курсоры проигрывают. Обидно ! :))) (Я привожу цифры для Oracle 9i, Windows 2000, Celeron 1,7 Mh)

Кол-во открытых и отпарсенных  курсоров, а также текст запросов  можно увидеть с помощью v$open_cursor:

select sql_text from v$open_cursor where user_name = USER;

Также кол-во текущих открытых  курсоров в v$mystat:

select count(*) from v$mystat where statistic# = 3;

 

Но если Вы посмотрите на v$open_cursor, то Вы не увидите там наших запросов ?!! Это потому, что курсоры были нами закрыты, а кешировать мы их не разрешили (см. session_cached_cursors ниже) 

Посмотрим наконец на параметры влияющие на наши курсоры:

SQL> show parameter cursor

NAME TYPE VALUE
------------------------------------ ----------- -----------------------
cursor_sharing string EXACT
cursor_space_for_time boolean FALSE
open_cursors integer 300
session_cached_cursors integer 0

 

open_cursors

Сколько открытых курсоров может иметь пользовательский процесс одновременно. Под этот параметр резервируется память при старте экземпляра. Сколько памяти ? Я думаю что оценить это можно с помощью запроса до и после изменения этого параметра:

select a.name, b.value  from v$statname a, v$mystat b  where a.statistic# = b.statistic# and lower(a.name) like 'session%memory%'

 

Когда я увеличил значение open_cursors с 300 до 1000, значение session_pga_memory также увеличилось.

cursor_sharing (metalink reference note)

Этот параметр показывает как Oracle будет производить поиск вашего курсора в SGA. 

  • EXACT

    Текст запроса должен совпадать точно. 

  •  FORCE

    Текст запроса может быть с точностью до bind переменных. Это очень полезно если программисты не знали про то что нужно использовать bind переменные и писали прямо where name = 'пупкин'. И таких запросов у Вас в SGA очень много. 

  • SIMILAR (начиная с 9i)

    Тоже что и FORCE, но при этом проверяется не изменится ли план запроса, если будет подобран подходящий курсор из уже распарсенных.

cursor_space_for_time (metalink reference note)

Этот параметр  позволяет держать в SGA связанные с закрытым курсором SQL Area, что позволяет инициировать курсор быстрее. Но использовать его рекомендуется только когда  в SGA достаточно свободного места.

session_cached_cursors (metalink reference note)

Показывает сколько вы хотите курсоров держать открытыми в сессии, даже несмотря на их явное закрытие в коде. Это позволяет избежать повторного hard парсинга и уменьшить количесво latch в вашем приложении. Об отличии hard от soft и влиянии этого параметра написал Tom Kyte

Проведем интересный эксперимент. Выставим cursor_sharing = EXACT, и session_cached_cursor = 20. Выполним время выполнения обоих скриптов начинает выравниваться (!), но не значительно.   Также в v$open_cursor появятся наши select from dual.

И наконец что же делать с упоминаемой в начала ошибкой ORA-1000.  Ну во первых посмотреть на значение параметра open_cursors. Значение в 200-300 должно хватать для большинства задач. Дальше посмотреть, а не увеличивается ли значение числа открытых курсоров во времени, возможно их просто забывают закрывать ? Используются ли bind переменные в вашем приложение, и каково значение  параметра cursor_sharing.

Конечно нужно прочитать что рекомендует в этом случае metalink

Dsvolk > > Oracle > > Faq > > Cursors Last Modified: 18-02-2003 12:33