SQL Server всегда использует сочетание операторов Split, Sort и Collapse при ведении уникального индекса как часть обновления, которое влияет (или может влиять) на несколько строк.
Работая с примером в вопросе, мы могли бы написать обновление как отдельное однострочное обновление для каждой из четырех представленных строк:
-- Per row updates
UPDATE dbo.Banana SET pk = 2 WHERE pk = 1;
UPDATE dbo.Banana SET pk = 3 WHERE pk = 2;
UPDATE dbo.Banana SET pk = 4 WHERE pk = 3;
UPDATE dbo.Banana SET pk = 5 WHERE pk = 4;
Проблема в том, что первый оператор потерпит неудачу, поскольку он изменяется pk
с 1 на 2, и уже есть строка, где pk
= 2. Механизм хранения SQL Server требует, чтобы уникальные индексы оставались уникальными на каждом этапе обработки, даже в пределах одного оператора. , Это проблема, решаемая с помощью Split, Sort и Collapse.
Трещина
Первым шагом является разделение каждого оператора обновления на удаление с последующей вставкой:
DELETE dbo.Banana WHERE pk = 1;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Оператор Split добавляет столбец кода действия в поток (здесь он помечен как Act1007):
Код действия: 1 для обновления, 3 для удаления и 4 для вставки.
Сортировать
Вышеуказанные операторы split по-прежнему приводят к ложному временному нарушению уникального ключа, поэтому следующим шагом будет сортировка операторов по ключам обновляемого уникального индекса ( pk
в данном случае), а затем по коду действия. Для этого примера это просто означает, что delete (3) на том же ключе упорядочены перед вставками (4). Итоговый порядок:
-- Sort (pk, action)
DELETE dbo.Banana WHERE pk = 1;
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
коллапс
Предшествующего этапа достаточно, чтобы гарантировать избежание ложных нарушений уникальности во всех случаях. В качестве оптимизации Collapse объединяет смежные удаления и вставляет одно и то же значение ключа в обновление:
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1;
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2;
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3;
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Пары удаления / вставки для pk
значений 2, 3 и 4 были объединены в обновление, в результате чего единственное удаление при pk
= 1, а вставка при pk
= 5.
Оператор свертывания группирует строки по ключевым столбцам и обновляет код действия для отражения результата свертывания:
Обновление кластерного индекса
Этот оператор помечен как Обновление, но он способен вставлять, обновлять и удалять. То, какое действие выполняет обновление кластеризованного индекса для строки, определяется значением кода действия в этой строке. У оператора есть свойство Action, отражающее этот режим работы:
Счетчики модификации строк
Обратите внимание, что три вышеприведенных обновления не изменяют ключ (и) поддерживаемого уникального индекса. По сути, мы преобразовали обновления ключевых столбцов в индексе в обновления неключевых столбцов ( c1
и c2
), а также удаления и вставки. Ни удаление, ни вставка не могут привести к ложному нарушению уникального ключа.
Вставка или удаление влияют на каждый столбец в строке, поэтому счетчики изменений, связанные с каждым столбцом, будут увеличиваться. При обновлении (обновлениях) только статистические данные с любым из обновленных столбцов в качестве ведущего столбца увеличивают свои счетчики изменений (даже если значение не изменяется).
Поэтому счетчики изменений строки статистики показывают 2 изменения pk
, и 5 для c1
и c2
:
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1; -- All columns modified
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4; -- c1 and c2 modified
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z'); -- All columns modified
Примечание. Только изменения, примененные к базовому объекту (куча или кластерный индекс), влияют на счетчики изменений строк статистики. Некластеризованные индексы являются вторичными структурами, отражающими изменения, уже внесенные в базовый объект. Они вообще не влияют на счетчики модификации строк статистики.
Если объект имеет несколько уникальных индексов, отдельная комбинация Split, Sort, Collapse используется для организации обновлений каждого из них. SQL Server оптимизирует этот случай для некластеризованных индексов, сохраняя результат Split в буферную таблицу Eager, а затем воспроизводит этот набор для каждого уникального индекса (который будет иметь свою собственную сортировку по ключам индекса + код действия и Collapse).
Влияние на обновления статистики
Автоматическое обновление статистики (если включено) происходит, когда оптимизатору запросов требуется статистическая информация и он отмечает, что существующая статистика устарела (или недействительна из-за изменения схемы). Статистика считается устаревшей, когда количество зарегистрированных изменений превышает пороговое значение.
Расположение «Сплит / Сортировка / Свернуть» приводит к различным модификаций строк, чем ожидалось. Это, в свою очередь, означает, что обновление статистики может быть инициировано раньше или позже, чем было бы в противном случае.
В приведенном выше примере количество модификаций строки для ключевого столбца увеличивается на 2 (чистое изменение), а не на 4 (по одному на каждую затронутую строку таблицы) или на 5 (по одному на каждое удаление / обновление / вставку, созданное в Свернуть).
Кроме того, неключевые столбцы, которые логически не были изменены исходным запросом, накапливают модификации строк, которые могут насчитывать до двух обновленных строк таблицы (по одному для каждого удаления и по одному для каждой вставки).
Количество записанных изменений зависит от степени перекрытия между старыми и новыми значениями ключевого столбца (и, таким образом, степень, в которой отдельные удаления и вставки могут быть свернуты). Сбрасывая таблицу между каждым выполнением, следующие запросы демонстрируют влияние на счетчики модификации строк с разными перекрытиями:
UPDATE dbo.Banana SET pk = pk + 0; -- Full overlap
UPDATE dbo.Banana SET pk = pk + 1;
UPDATE dbo.Banana SET pk = pk + 2;
UPDATE dbo.Banana SET pk = pk + 3;
UPDATE dbo.Banana SET pk = pk + 4; -- No overlap