Добавить в корзинуПозвонить
Найти в Дзене
Oracle Developer

Миф: явный курсор работает быстрее неявного

🧐 Друзья, всем привет! С вами Костя Андронов 👋 Сегодня разберём миф, который дожил с 90-х: «явный курсор эффективнее неявного». 🕰 Откуда ноги растут В 7 версии Oracle (PL/SQL 2.2) неявный курсор действительно был медленнее. По стандарту ANSI SQL запрос на одну строку обязан убедиться, что строка ровно одна — значит, делается второй FETCH, чтобы поймать TOO_MANY_ROWS. 2 FETCH вместо 1 — отсюда легенда. В следующем релизе PL/SQL 2.3 неявные курсоры оптимизировали, и с тех пор они работают чуть быстрее явных. Но миф жив до сих пор 🤯 ⚙️ Три варианта на примере SELECT INTO — короткий, читаемый, но обязан получить ровно одну строку: declare v_name employees.last_name%type; begin select last_name into v_name from employees where employee_id = 100; exception when no_data_found then null; -- обработка end; OPEN/FETCH/CLOSE — больше кода, зато полный контроль: проверяем %NOTFOUND без exception: declare cursor c is select last_name from employees where employee_id = 100; v_name em

Миф: явный курсор работает быстрее неявного 🧐

Друзья, всем привет!

С вами Костя Андронов 👋

Сегодня разберём миф, который дожил с 90-х: «явный курсор эффективнее неявного».

🕰 Откуда ноги растут

В 7 версии Oracle (PL/SQL 2.2) неявный курсор действительно был медленнее. По стандарту ANSI SQL запрос на одну строку обязан убедиться, что строка ровно одна — значит, делается второй FETCH, чтобы поймать TOO_MANY_ROWS. 2 FETCH вместо 1 — отсюда легенда.

В следующем релизе PL/SQL 2.3 неявные курсоры оптимизировали, и с тех пор они работают чуть быстрее явных. Но миф жив до сих пор 🤯

⚙️ Три варианта на примере

SELECT INTO — короткий, читаемый, но обязан получить ровно одну строку:

declare

v_name employees.last_name%type;

begin

select last_name

into v_name

from employees

where employee_id = 100;

exception

when no_data_found then

null; -- обработка

end;

OPEN/FETCH/CLOSE — больше кода, зато полный контроль: проверяем %NOTFOUND без exception:

declare

cursor c is

select last_name

from employees

where employee_id = 100;

v_name employees.last_name%type;

begin

open c;

fetch c into v_name;

if c%notfound

then

null; -- обработка

end if;

close c;

end;

Cursor FOR Loop — компактно для множества строк, Oracle сам открывает/закрывает:

begin

for r in (select last_name

from employees

where department_id = 10)

loop

dbms_output.put_line(r.last_name);

end loop;

end;

📊 Что говорят цифры

Steven Feuerstein (Oracle ACE, автор книг по PL/SQL) прогнал бенчмарк на 100 000 итераций (оригинальная статья тут) . Поиск одной строки, которая есть в таблице:

🔹 SELECT INTO — 4.703 сек

🔹 Cursor FOR Loop — 4.685 сек

🔹 OPEN/FETCH/CLOSE — 5.209 сек

А вот когда строки нет:

🔸 SELECT INTO — 6.372 сек (NO_DATA_FOUND стоит дорого)

🔸 Cursor FOR Loop — 4.560 сек

🔸 OPEN/FETCH/CLOSE — 4.703 сек

На «холостых» запросах генерация исключения NO_DATA_FOUND из SELECT INTO съедает всё преимущество.

🧭 Когда что выбирать

✅ SELECT INTO — одна строка, и она почти всегда есть. Дефолтный выбор.

✅ OPEN/FETCH/CLOSE — одна строка, и «не нашли» — частый случай. Избегаем дорогого NO_DATA_FOUND.

Но с точки зрения читаемости явные курсоры проигрывают: код громоздкий, сам запрос вынесен в секцию`declare` — и потом приходится возвращаться к нему глазами, чтобы понять, что за данные пошли в бизнес-логику. Плюс важно не забывать закрывать курсор — об этом разработчики регулярно забывают.

🤔А что насчёт цикла FOR для гарантированно одной строки?

Работает он быстро, но при чтении кода интуитивно сбивает: такой цикл обычно ассоциируется с многострочными запросами. Можно добавить явный exit; в конце цикла — тогда видно, что он отработает только для одной строки, но и не будет исключения если запрос вернет несколько строк и результат будет неожиданным. Использовать ли такой вариант — решайте сами, по производительности он не уступает.

Итог 🧩

«Явный курсор быстрее» — это про 7 Oracle из эпохи модемов. Сегодня правило другое: смотрите не на тип курсора, а на то, что вероятнее — найти строку или промахнуться.

А вообще производительность чаще страдает совсем не от выбора типа курсора — а от десятков других причин, которые разбираем на курсе по оптимизации.

А вы какой курсор используете по умолчанию? Делитесь в Чатике — обсудим ваши кейсы 💬

С вами был Костя. Хорошего дня и быстрых запросов! 🚀

#oracle #plsql #курсоры #оптимизация #базы_данных #Konstantin_Andronov

Канал Oracle Developer | Чатик 💬

Мини-курс Оптимизация: Быстрый старт 🚀

📱 YouTube 📱 ВКонтакте 📱 LinkedIn 📱Threads

RUTUBE