Почему реляционные запросы на основе наборов лучше, чем курсоры?

Запросы на основе множества sql-query (обычно) быстрее, потому sql что:

  1. У них есть больше информации для оптимизатора запросов
  2. Они могут выполнять пакетное чтение с диска
  3. Требуется меньше журналов для откатов, журналов транзакций и т. д.
  4. Берется меньше блокировок, что снижает накладные расходы
  5. Логика, основанная на наборах, находится в центре внимания РСУБД, поэтому они были сильно оптимизированы для нее (часто за счет процедурной производительности)

Перенос данных на промежуточный cursor уровень для их обработки cursor может быть полезен, поскольку language-agnostic он снимает нагрузку с сервера sql-select БД (который труднее всего language-agnostic масштабировать, и обычно select-statement он выполняет и другие задачи). Кроме sql-query того, у вас обычно нет таких language-agnostic же накладных расходов (или language-agnostic преимуществ) на среднем уровне. Такие sql-select вещи, как журналирование cursor транзакций, встроенная блокировка sql-query и блокировка и т. д. — иногда sqlselect они необходимы и полезны, а language-independent иногда — просто пустая трата sql-query ресурсов.

Простой курсор с language-independent процедурной логикой по сравнению sql с примером на основе набора cursor (T-SQL), который будет назначать sqlselect код города на основе телефонной sql-statement станции:

--Cursor
DECLARE @phoneNumber char(7)
DECLARE c CURSOR LOCAL FAST_FORWARD FOR
   SELECT PhoneNumber FROM Customer WHERE AreaCode IS NULL
OPEN c
FETCH NEXT FROM c INTO @phoneNumber
WHILE @@FETCH_STATUS = 0 BEGIN
   DECLARE @exchange char(3), @areaCode char(3)
   SELECT @exchange = LEFT(@phoneNumber, 3)

   SELECT @areaCode = AreaCode 
   FROM AreaCode_Exchange 
   WHERE Exchange = @exchange

   IF @areaCode IS NOT NULL BEGIN
       UPDATE Customer SET AreaCode = @areaCode
       WHERE CURRENT OF c
   END
   FETCH NEXT FROM c INTO @phoneNumber
END
CLOSE c
DEALLOCATE c
END

--Set
UPDATE Customer SET
    AreaCode = AreaCode_Exchange.AreaCode
FROM Customer
JOIN AreaCode_Exchange ON
    LEFT(Customer.PhoneNumber, 3) = AreaCode_Exchange.Exchange
WHERE
    Customer.AreaCode IS NULL

sql

language-agnostic

cursor

2022-06-13T14:12:32+00:00