Как SQL Server обрабатывает операторы SELECT в транзакционной вставке? - PullRequest
2 голосов
/ 27 июня 2011

В рамках процесса закрытия розничной торговли существует транзакционная хранимая процедура, которая выбирает из каждой из 18 таблиц и вставляет их в отдельную базу данных для последующей обработки мэйнфрейма. Эта процедура демонстрирует некоторые странные временные характеристики, и я думаю, что это из-за фундаментального недопонимания того, как транзакции работают в SQL Server.

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

Хранимая процедура выполняется на основе запроса пользователя и выглядит примерно так:

BEGIN TRANSACTION

INSERT INTO Table1
        (Column1,
        Column2,
        Column3,
        Column4,
        Column5,
        Column6,
        Column7,
        Column8)
    SELECT
        Column1,
        Column2,
        Column3,
        Column4,
        Column5,
        Column6,
        Column7,
        Column8
    FROM
        OLTPTable T
    INNER JOIN
        LookupTable1 L
    ON  
        T.Foreign = L.Key

INSERT INTO Table2
        (Column1,
        Column2,
        Column3)
    SELECT
        Column1,
        Column2,
        Column3
    FROM
        OLTPTable2 T
    INNER JOIN
        LookupTable2 L
    ON  
        T.Foreign = L.Key

INSERT INTO Table3
        (Column1,
        Column2,
        Column3,
        Column4,
        Column5,
        Column6)
    SELECT
        Column1,
        Column2,
        Column3,
        Column4,
        Column5,
        Column6
    FROM
        OLTPTable3 T
    INNER JOIN
        LookupTable3 L
    ON  
        T.Foreign = L.Key

-- Through Table 18 and OLTP Table 18

COMMIT TRANSACTION

Регистрация выглядит примерно так:

Table1      0.2 seconds 354 rows
Table2      7.4 seconds 35 rows
Table3      3.9 seconds 99 rows

Нет четкой корреляции между количеством строк или сложностью объединений и временем.

У меня вопрос - на такой длительной процедуре, каков эффект транзакции? Блокирует ли все таблицы в подселектах в начале? Один за раз? Ожидание, пока исходная таблица станет доступной для блокировки, что вызывает ожидания?

Ответы [ 3 ]

4 голосов
/ 27 июня 2011

При уровне изоляции READ COMMITTED по умолчанию блокировки Read (shared) будут присутствовать только в течение каждого SELECT. Не для транзакции.

Чтобы изменить это, вам потребуется REPEATABLE_READ на более высоком уровне, чтобы сохранить общую блокировку (чтение) до конца транзакции.

Примечания:

  • детализация блокировки (строка, страница и т. Д.) Отдельно от этой длительности
  • другие процессы смогут читать таблицы SELECTed

Ваша длительность ВСТАВКИ будет зависеть от целого ряда условий. Некоторые из:

Редактировать:

После долгих размышлений, вам лучше использовать sp_getapplock и т. Д. Для поддержки параллелизма на уровне приложения.

2 голосов
/ 27 июня 2011

Под каким уровнем изоляции?

Для части записи (вставки) все одинаково, независимо от уровня изоляции: все вставленные строки заблокированы в режиме X до конца конца транзакции. Блокировки строк могут перерасти в блокировки таблиц.

Если уровень изоляции оставлен по умолчанию read commit и опция read-commit-snapshot-изоляция в базе данных отключена, то все будет происходить так: каждый выбор будет блокировать по одной строке за раз в режиме S и выпустит его немедленно.

При повторяющемся чтении изоляция S-блокировок, полученных SELECT, будет сохраняться до конца транзакции, и они могут перерасти в блокировку таблицы S.

При сериализуемом чтении изоляция SELECT получит блокировки диапазона вместо блокировок строк и сохранит их до конца транзакции. Опять может произойти эскалация блокировки.

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

В режиме фиксации чтения при включении read-commit-snapshot-изоляция в базе данных, SELECT не будут получать никаких блокировок, вместо этого они будут читать из хранилища версий, если строка заблокирована. Чтение версии соответствует снимку значения в начале оператора.

Теперь вернемся к вашему вопросу: почему вы видите различия в производительности? Как и в случае с любым вопросом о производительности, лучше всего применять методологию расследования, а Waits and Queues - отличная. Как только вы исследуете основную причину, может быть предложено правильное решение.

2 голосов
/ 27 июня 2011

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

...