Поделиться через


Рекомендации по логике повторных попыток для транзакций в таблицах Memory-Optimized

Существуют условия ошибки, возникающие с транзакциями, которые обращаются к таблицам, оптимизированным для памяти.

    1. Текущая транзакция попыталась обновить запись, обновленную с момента начала транзакции.
    1. Текущей транзакции не удалось выполнить фиксацию из-за ошибки проверки уровня изоляции REPEATABLE READ.
    1. Текущей транзакции не удалось выполнить фиксацию из-за ошибки сериализуемой проверки.
    1. Предыдущая транзакция, на которую опиралась текущая транзакция, отменена, и текущая транзакция больше не может быть подтверждена.

Распространенной причиной этих ошибок является вмешательство между параллельно выполняемыми транзакциями. Обычное исправление — повторить транзакцию.

Дополнительные сведения об этих условиях ошибки см. в разделе об обнаружении конфликтов, проверке и фиксации проверок зависимостей в транзакциях в таблицах Memory-Optimized.

Взаимоблокировки (код ошибки 1205) не могут возникать в таблицах, оптимизированных для памяти. Блокировки не используются для оптимизированных для памяти таблиц. Однако если приложение уже содержит логику повтора для взаимоблокировок, можно расширить существующую логику, чтобы включить новые коды ошибок.

Рекомендации по повторным попыткам

Приложения обычно сталкиваются с конфликтами между транзакциями и должны реализовать логику повторных попыток, чтобы устранить эти конфликты. Количество конфликтов, возникающих в зависимости от ряда факторов:

  • Конкуренция за отдельные строки. Потенциал конфликтов увеличивается по мере увеличения числа транзакций, пытающихся обновить ту же строку.

  • Количество строк, считываемых транзакциями REPEATABLE READ. Чем больше строк считывается, тем больше вероятность того, что некоторые из этих строк обновляются параллельными транзакциями. Это приводит к повторяемым сбоям проверки чтения.

  • Размер диапазонов сканирования, используемых транзакциями SERIALIZABLE. Чем больше диапазоны сканирования, тем выше вероятность того, что параллельные транзакции будут вводить фантомные строки, вызывая сбои сериализуемой проверки.

    Приложению трудно избежать этих конфликтов, требуя логики повторных попыток.

Это важно

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

Рекомендации по транзакциям Read-Only и нативно скомпилированным хранимым процедурам

Транзакции только для чтения, охватывающие одно выполнение скомпилированной хранимой процедуры, не требуют проверки для транзакций REPEATABLE READ и SERIALIZABLE. Конфликты записи не могут возникать из-за транзакции, доступной только для чтения.

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

Рекомендации по Read-Only транзакциям и межконтейнерным транзакциям

Транзакции только для чтения, запущенные вне контекста нативно скомпилированной хранимой процедуры, не выполняют проверку, если оптимизированные для памяти таблицы доступны при изоляции SNAPSHOT. Однако при доступе к оптимизированным для памяти таблицам с использованием изоляции REPEATABLE READ или SERIALIZABLE, проверка выполняется в момент фиксации транзакции. В этом случае может потребоваться логика повторных попыток.

Дополнительные сведения см. в разделе о межконтейнерных транзакциях на уровнях изоляции транзакций.

Реализация логики повторных попыток

Как и во всех транзакциях, обращаюющихся к таблицам, оптимизированным для памяти, необходимо рассмотреть логику повторных попыток для обработки потенциальных сбоев, таких как конфликты записи (код ошибки 41302) или сбои зависимостей (код ошибки 41301). В большинстве приложений скорость сбоя будет низкой, но все равно необходимо обрабатывать сбои, повторив транзакцию. Ниже приведены два предлагаемых способа реализации логики повторных попыток.

  • Повторные попытки на стороне клиента. Повторные попытки на стороне клиента — предпочтительный способ реализации логики повторных попыток в общем случае. Клиентское приложение перехватывает ошибку, вызванную транзакцией, и повторяет транзакцию. Если существующее клиентское приложение имеет логику повторных попыток для обработки взаимоблокировок, можно расширить приложение для обработки новых кодов ошибок.

  • Использование обертки хранимой процедуры. Клиент вызывает интерпретированную Transact-SQL хранимую процедуру, которая вызывает нативно скомпилированную хранимую процедуру или выполняет транзакцию. Затем процедура оболочки использует логику try/catch, чтобы поймать ошибку и повторить вызов процедуры при необходимости. Возможно, результаты возвращаются клиенту до сбоя, и клиент не знает, что их следует выбросить. Поэтому, для надежности, рекомендуется использовать этот метод только с нативно скомпилированными хранимыми процедурами, которые не возвращают результирующие наборы клиенту.

Логика повторных попыток может быть реализована в Transact-SQL или в коде приложения в середине уровня.

Ниже приведены две возможные причины для рассмотрения логики повторных попыток:

  • Клиентское приложение имеет логику повтора для других кодов ошибок, таких как 1205, которые можно расширить.

  • Конфликты редки, и важно уменьшить сквозную задержку с помощью предварительно подготовленного выполнения. Дополнительные сведения о выполнении хранимых процедур, скомпилированных в собственном коде, см. в разделе "Скомпилированные в собственном коде хранимые процедуры".

В следующем примере показана логика повторных попыток в интерпретируемой Transact-SQL хранимой процедуре, содержащей вызов скомпилированной в собственном коде хранимой процедуры или транзакции между контейнерами.

CREATE PROCEDURE usp_my_procedure @param1 type1, @param2 type2, ...  
AS  
BEGIN  
  -- number of retries - tune based on the workload  
  DECLARE @retry INT = 10  
  
  WHILE (@retry > 0)  
  BEGIN  
    BEGIN TRY  
  
      -- exec usp_my_native_proc @param1, @param2, ...  
  
      --       or  
  
      -- BEGIN TRANSACTION  
      --   ...  
      -- COMMIT TRANSACTION  
  
      SET @retry = 0  
    END TRY  
    BEGIN CATCH  
      SET @retry -= 1  
  
      -- the error number for deadlocks (1205) does not need to be included for   
      -- transactions that do not access disk-based tables  
      IF (@retry > 0 AND error_number() in (41302, 41305, 41325, 41301, 1205))  
      BEGIN  
        -- these error conditions are transaction dooming - rollback the transaction  
        -- this is not needed if the transaction spans a single native proc execution  
        --   as the native proc will simply rollback when an error is thrown   
        IF XACT_STATE() = -1  
          ROLLBACK TRANSACTION  
  
        -- use a delay if there is a high rate of write conflicts (41302)  
        --   length of delay should depend on the typical duration of conflicting transactions  
        -- WAITFOR DELAY '00:00:00.001'  
      END  
      ELSE  
      BEGIN  
        -- insert custom error handling for other error conditions here  
  
        -- throw if this is not a qualifying error condition  
        ;THROW  
      END  
    END CATCH  
  END  
END  

См. также

Общие сведения о транзакциях в таблицах Memory-Optimized
Транзакции в таблицах Memory-Optimized
Рекомендации по уровням изоляции транзакций с таблицами Memory-Optimized