Я пытаюсь обновить целевую таблицу, которая имеет одну строку размером 5 КБ и строку размером 5 КБ.
Поскольку это одна строка, легко узнать фактический размер строки:
select *
from sys.dm_db_index_physical_stats(DB_ID('RODS_HSD_ES'),
OBJECT_ID(N'TBL_BM_HSD_SUBJECT_AN_148_REPRO'), NULL, NULL, 'DETAILED')
Таблица не была изменена с момента создания. не вижу никакой причины, почему он должен потерпеть неудачу. Идеи?
sql-server
sql-server-2012
update
Йоси Дахари
источник
источник
Ответы:
Проблема связана с тем, что вы обновляете ключ кластеризации, и у таблицы назначения есть схема разделения 1 . Когда SQL Server запрашивается обновить любой компонент ключа кластеризации, он должен выполнить
UPDATE
DELETE
гибридное обновление и , или, где некоторые строки обновляются на месте, а некоторые нет.Если вы удалите кластерный индекс из таблицы назначения, вы увидите, что обновление работает.
Сообщение об ошибке, хотя, возможно, немного вводит в заблуждение, является точным, поскольку размер результирующего строки во время обновления превышает максимальную длину.
Я предлагаю вам рассмотреть вопрос об изменении структуры таблицы:
VARCHAR(MAX)
для всех этих столбцов. Если вам на самом деле не нужно 2 ГБ символов в одном столбце, зачем определять столбец таким образом? Определите столбец как максимальный размер, который будет реально встречаться.V_MAX_xxx
,V_64_xxx
иV_512_xxx
колонны, и т.д.Чтобы упростить ваше воспроизведение, вы можете удалить курсор и выполнить только следующую операцию DML:
Приведенный выше столбец является одним из компонентов ключа кластеризации, а также ключа разделения (обновление других столбцов ключа CI работает нормально).
С кластеризованным индексом вы получите эту ошибку:
Без кластерного индекса оператор выполняется успешно.
1 Интересно, что если мы исключим разделение из репродукции, мы обнаружим, что обновление прошло успешно даже при наличии кластерного индекса.
источник
Обновление не выполняется по причинам, сходным с теми, которые я объяснил в ответ на ваш предыдущий вопрос .
В этом случае, потому что вы потенциально обновление нескольких строк , где ключевой столбец из уникального индекса является изменен * , SQL Server создает план , который включает в себя Split, сортировке и оператор Collapse , чтобы избежать промежуточных уникальных нарушений основных (см этой статьи для более подробной информации) ,
Введенный таким образом оператор сортировки встречает промежуточную строку (включая внутренние издержки) шириной, превышающей предел, поэтому возникает ошибка. Добавление
OPTION (ROBUST PLAN)
подсказки к запросу на обновление показывает, что это неизбежно:Отношения источника и цели данных неясны для меня из краткого обзора, но если вы можете гарантировать, что каждая операция обновления повлияет не более чем на одну строку, вы можете избежать необходимости разделения / сортировки / свертывания, добавив
TOP (1)
в оператор обновления:Это немного взломать, хотя. В идеале, структура оператора обновления и индексы должны предоставлять оптимизатору достаточно информации, чтобы он мог видеть, что будет обновлено не более одной строки. В частности, рекомендуется писать операторы обновления, которые являются детерминированными .
Учитывая странный дизайн и отсутствие ясности в вопросе, я даже не собираюсь пытаться расшифровать отношения данных или изменения запросов и индексов, которые были бы необходимы для достижения этого в деталях.
* Как отметил Мартин Смит в комментарии, это не было бы проблемой в данной конкретной ситуации, если бы таблица не была разделена. Если обновление устанавливает ключ в одно и то же детерминированное значение в каждой строке, Split / Sort / Collapse не требуется, если только таблица не разделена на этот ключ. Таким образом, альтернативное решение для этого запроса - не разбивать таблицу на время выборки .
источник