← Назад к вопросам

Что такое курсор в БД?

2.2 Middle🔥 61 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое курсор в контексте баз данных?

В реляционных базах данных курсор — это объект базы данных, который предоставляет механизм для последовательного, пошагового перебора строк в результирующем наборе данных, полученном в результате выполнения SQL-запроса (обычно SELECT). Вместо обработки всего набора результатов как единого блока (что может потребовать значительных ресурсов памяти), курсор позволяет работать с одной строкой за раз, подобно указателю на текущую запись в наборе.

Грубую аналогию можно провести с чтением книги: вы можете открыть книгу на любой странице (позиционирование) и читать построчно (последовательная обработка), вместо того чтобы загружать всё её содержимое в оперативную память сразу.

Основные свойства и типы курсоров

Курсоры классифицируются по нескольким ключевым признакам:

  1. По направлению перемещения:
    *   **Однопроходные (Forward-only / Non-scrollable):** Перемещение возможно только вперёд, от первой строки к последней. Наиболее простые и быстрые.
    *   **Прокручиваемые (Scrollable):** Позволяют перемещаться в любом направлении (`FIRST`, `LAST`, `PRIOR`, `NEXT`, `RELATIVE`, `ABSOLUTE`). Требуют больше ресурсов.

  1. По чувствительности к изменениям данных:
    *   **Статические (Static / Insensitive):** Создают снимок (snapshot) данных на момент открытия курсора. Все последующие изменения в таблице (другими транзакциями или командами) не видны через этот курсор.
    *   **Динамические (Dynamic):** Наиболее ресурсоёмкие. Видят все изменения, происходящие в данных, даже если они совершены другими операциями после открытия курсора.
    *   **Набор ключей (Keyset-driven):** Запоминает только уникальные идентификаторы (ключи) строк. Сами данные могут обновляться, но добавление или удаление строк видно не будет.

  1. По способу работы с транзакциями (уровень изоляции): Поведение курсора сильно зависит от настроек изоляции транзакции, в которой он открыт.

Жизненный цикл курсора

Работа с курсором в SQL (например, в стандарте SQL или СУБД вроде PostgreSQL, SQL Server) следует строгой последовательности:

-- 1. ОБЪЯВЛЕНИЕ (DECLARE): Определяем запрос и свойства курсора.
DECLARE employee_cursor SCROLL CURSOR
    FOR SELECT id, name, salary FROM employees WHERE department_id = 10;

-- 2. ОТКРЫТИЕ (OPEN): Выполнение запроса и формирование результирующего набора.
OPEN employee_cursor;

-- 3. ВЫБОРКА ДАННЫХ (FETCH): Последовательное извлечение строк.
FETCH NEXT FROM employee_cursor; -- Первая строка
-- ... здесь обработка данных ...
FETCH ABSOLUTE 5 FROM employee_cursor; -- Пятая строка (если курсор прокручиваемый)

-- 4. ЗАКРЫТИЕ (CLOSE): Освобождение набора данных, но с возможностью переоткрытия.
CLOSE employee_cursor;

-- 5. УДАЛЕНИЕ (DEALLOCATE): Полное освобождение ресурсов, связанных с курсором.
DEALLOCATE employee_cursor;

Практическое применение и пример в PHP (PDO)

В PHP, при работе с БД через PDO, курсоры часто используются неявно. Однако можно управлять ими явно, например, для обработки больших результатов без полной загрузки в память.

<?php
$pdo = new PDO('pgsql:host=localhost;dbname=test', 'user', 'pass');

// Явное указание на использование однонаправленного курсора на стороне сервера
$sql = 'SELECT id, name, large_text_field FROM huge_table';
$stmt = $pdo->prepare($sql, [
    PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, // Запрос прокручиваемого курсора
]);

$stmt->execute();

// Извлекаем данные по одной строке, не загружая весь набор
while ($row = $stmt->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) {
    // Обработка каждой строки, например, потоковая выдача или сложные вычисления
    processLargeRow($row['large_text_field']);
    // На этом этапе в памяти PHP находится только одна строка результата
}

function processLargeRow($data) {
    // Обработка данных строки
}
?>

Преимущества и недостатки

Когда использовать курсоры:

  • Обработка очень больших результирующих наборов, которые невозможно целиком поместить в память приложения.
  • Необходимость последовательной, поэтапной обработки строк с сложной бизнес-логикой между операциями FETCH.
  • Инкрементальные операции, когда для каждой строки нужно выполнить дополнительный запрос или сторонний API-вызов.

Когда ИЗБЕГАТЬ курсоров (критически важно!):

  • Операции над множеством строк (UPDATE, DELETE, INSERT). Для них ВСЕГДА следует использовать наборные операции на чистом SQL с условием WHERE. Курсор здесь приведёт к "проклятию RBAR" (Row-By-Agonizing-Row) — колоссальному падению производительности из-за накладных расходов на каждую строку и блокировок.
  • Простые выборки данных для отображения. Гораздо эффективнее использовать LIMIT/OFFSET или ключи пагинации.
  • В веб-приложениях, где время выполнения запроса ограничено, длительные операции с курсорами могут быть неуместны.

Вывод

Курсор — это мощный, низкоуровневый инструмент для управления потоком обработки данных на уровне строк. Однако в современной разработке PHP Backend к нему следует прибегать осознанно и редко, в основном для решения специфических задач, связанных с обработкой больших данных, когда наборные SQL-операции неприменимы. В 95% случаев стандартных CRUD-операций и выборок данных эффективнее использовать оптимизированные SQL-запросы, работающие с множеством строк одновременно. Грамотный backend-разработчик должен уметь пользоваться курсорами, но прежде всего — знать, когда их использование является антипаттерном.

Что такое курсор в БД? | PrepBro