Ошибка ORA-01000: maximum open cursors exceeded в Oracle DB
- Ошибка
ORA-01000: maximum open cursors exceededв высоконагруженных приложениях и веб-сервисах. - Постепенная деградация производительности сессий и утечка памяти PGA.
- Количество открытых курсоров на одну сессию достигает установленного предела в параметре
open_cursors.
1. Проверка текущего лимита open_cursors
SHOW PARAMETER open_cursors;2. Поиск сессий с наибольшим числом открытых курсоров
SELECT a.sid, s.username, s.program, s.machine, a.value AS open_cursors
FROM v$sesstat a
JOIN v$statname b ON a.statistic# = b.statistic#
JOIN v$session s ON a.sid = s.sid
WHERE b.name = 'opened cursors current'
ORDER BY a.value DESC;3. Определение SQL-запросов, вызывающих утечку курсоров
SELECT c.sid, c.user_name, c.sql_text, COUNT(*)
FROM v$open_cursor c
WHERE c.sid = <SID_ИЗ_ПРЕДЫДУЩЕГО_ЗАПРОСА>
GROUP BY c.sid, c.user_name, c.sql_text
ORDER BY COUNT(*) DESC;4. Динамическое увеличение параметра open_cursors
Параметр можно изменить на лету без перезапуска экземпляра СУБД:
ALTER SYSTEM SET open_cursors=1500 SCOPE=BOTH;5. Исправление утечек курсоров в коде приложения
Убедитесь, что в коде (Java, C#, PL/SQL) все дескрипторы закрываются в блоках finally или через try-with-resources:
// Пример Java JDBC
try (PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) { /* processing */ }
} // Автоматическое закрытие ResultSet и Statement Частые вопросы (FAQ)
В чем разница между представлениями v$open_cursor и v$sesstat ('opened cursors current')?
v$open_cursor показывает курсоры, находящиеся в кэше сессии (Session Cached Cursors) плюс реально открытые. Истинное число удерживаемых открытых дескрипторов показывает только метрика 'opened cursors current' в v$sesstat.
Приводит ли увеличение open_cursors к высокому потреблению оперативной памяти?
Нет. Параметр open_cursors задает лишь верхний лимит. Память в PGA выделяется динамически только под фактически открытые дескрипторы.
Почему PL/SQL курсорные циклы FOR r IN (SELECT ...) не вызывают ORA-01000?
Неявные курсоры в циклах FOR r IN (...) управляются ядром PL/SQL автоматически — они открываются, читают данные с предвыборкой (bulk fetch) и гарантированно закрываются при выходе из блока.
Закрываются ли открытые курсоры при выполнении COMMIT?
По умолчанию обычные курсоры остаются открытыми после COMMIT. Только курсоры, объявленные с опцией WITH HOLD (в ряде интерфейсов) или закрытые явно через CLOSE, освобождают ресурсы.