KB956718 - ИСПРАВЛЕНО: инструкция merge может не применять ограничение внешнего ключа, если инструкция обновляет столбец уникального ключа, который не является частью ключа кластеризация и имеет одну строку в качестве источника обновления в SQL Server 2008

Применяется к
SQL Server 2008

Ошибка #: 50003167 (исправление SQL)

Дополнительные сведения о master списке сборок, выпущенных после выпуска SQL, см. в следующей статье базы знаний Майкрософт:

957826 Здесь можно найти дополнительные сведения о сборках SQL Server 2008, выпущенных после SQL Server 2008 г., и сборках SQL Server 2005 г., выпущенных после SQL Server 2005 с пакетом обновления 2 (SP2)

Проблема

В Microsoft SQL Server 2008 ограничение внешнего ключа может не применяться, если выполняются следующие условия:

  • Выдается заявление MERGE.
  • Целевой столбец обновления имеет некластеризованный уникальный индекс.

Рассмотрим следующий сценарий. Инструкция обновляет уникальный столбец с именем Column1 таблицы с именем Table1. На таблицу 1 ссылается ограничение внешнего ключа из таблицы с именем Table2.

В результате строки в таблице Table1 изменяются, когда этого не должно быть. Кроме того, в таблице Таблица2 будут строки с висячими ссылками на таблицу 1.

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

  • Указанный столбец "Столбец1" в таблице "Таблица1" не является частью ключа кластеризации таблицы 1.

  • Столбцу Column1 можно назначить только одно возможное значение. Например, может произойти один из следующих сценариев:

    • Источником слияния является одна строка данных. Например, источником слияния является одна из следующих операторов select:

      • select <ConstantValues>
        
      • select <Parameters>
        

      Примечание. Этот сценарий наиболее вероятен.

    • Источником слияния фактически является одна строка данных. Например, источником слияния является одна из следующих операторов select:

      • select <ColumnName> from <TableName> where <TableName>.<ColumnName> = 1
        

        Note <TableName>.<Оптимизатор запросов называет ColumnName> уникальным значением.

      • select top 1 <ColumnName> from <TableName>
        
    • Объединение источника и целевого объекта слияния имеет предикат, который гарантирует обновление одной строки.

    • Предложение update устанавливает для столбца Column1 постоянное значение независимо от источника слияния.

  • Параметр Каскад обновления не включен для ограничения внешнего ключа в таблице 2.

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

Решение

Исправление для этой проблемы впервые выпущено в накопительном пакете обновления 1. Для получения дополнительных сведений о том, как получить этот накопительный пакет обновления для SQL Server 2008, откройте статью со следующим номером в базе знаний Майкрософт:

956717 Накопительный пакет обновления 1 за SQL Server 2008 г.

Примечание. Поскольку сборки являются накопительными, каждый новый выпуск исправления содержит все исправления и исправления безопасности, которые были включены в предыдущий выпуск исправления SQL Server 2008. Рекомендуется рассмотреть возможность применения последнего выпуска исправления, содержащего это исправление. Для просмотра статьи в базе знаний Майкрософт щелкните следующий номер статьи:

956909 Сборки SQL Server 2008 г., выпущенные после выпуска SQL Server 2008 г.

Временное решение

Пакет исправлений устраняет проблему. Если оператор MERGE используется в сценарии, описанном в разделе "Симптомы", и исправление не применяется, выполните следующие действия, чтобы устранить эту проблему:

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

  2. Использовать флаг трассировки 8790. Этот флаг трассировки заставляет оптимизатор использовать своего рода план, который называется расширенным планом обновления. Широкие планы обновления не содержат этой проблемы. Этот шаг несет в себе риски для производительности всех инструкций DML. Поэтому следует избегать использования этого шага, если нет возможности изменить приложение.

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

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

use tempdb;

drop table sale, product;
create table product(pno int not null primary key, name char(30), pAlternateKey char(6) not null unique);
create table sale(sno int not null primary key, pAlternateKey char(6) not null references product(pAlternateKey));
insert product values(1, 'Office Chair', 'ochair');
insert sale values(1, 'ochair')

-- No violation of foreign key constraint is detected. However, one should be.
merge into product
using (select 'Office Chair2' as name, 1 as pno, 'oxx' as pAlternateKey) as src
on product.pno = src.pno
when matched then
   update set product.pAlternateKey = src.pAlternateKey, 
              product.name = src.name
when not matched then
   insert values(src.pno, src.name, src.pAlternateKey);

Измените сценарий так, чтобы он выглядел примерно так:

insert product values(1, 'Office Chair', 'ochair');
insert sale values(1, 'ochair')
-- A foreign key constraint violation is detected, and the update fails.
declare @source table 
   (name nchar(30), pno int, pAlternateKey nchar(30));
insert into @source values('Office Chair2',1,'oxx');

merge into product
using @source as src
on product.pno = src.pno
when matched then
   update set product.pAlternateKey = src.pAlternateKey, 
              product.name = src.name
when not matched then
   insert values(src.pno, src.name, src.pAlternateKey);

Состояние

Корпорация Майкрософт подтвердила, что это проблема продуктов Microsoft, перечисленных в разделе «Относится к».

Дополнительные сведения

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

956717 Накопительный пакет обновления 1 за SQL Server 2008 г.

Ссылки

Дополнительные сведения о списке сборок, доступных после выпуска SQL Server 2008, см. в следующей статье базы знаний Майкрософт:

956909 Сборки SQL Server 2008 г., выпущенные после выпуска SQL Server 2008 г.

Дополнительные сведения о модели добавочного обслуживания для SQL Server см. в следующей статье базы знаний Майкрософт:

935897 Команда SQL Server предоставляет модель добавочного обслуживания для предоставления исправлений для обнаруженных проблем

Дополнительные сведения о схеме именования для обновлений SQL Server см. в следующей статье базы знаний Майкрософт:

822499 Новая схема именования пакетов обновления программного обеспечения Microsoft SQL Server

Дополнительные сведения о терминологии обновления программного обеспечения см. в следующей статье базы знаний Майкрософт:

824684 Стандартные термины, используемые при описании обновлений программного обеспечения Майкрософт

Некластеризованные индексы в SQL Server 2008

Дополнительные сведения о некластеризованных индексах в SQL Server 2008 см. на следующем веб-сайте Microsoft Developer Network (MSDN):

https://msdn.microsoft.com/library/ms179325(sql.100).aspx