KB956718 – КОРЕКЦИЯ: Командата за обединяване може да не налага ограничение на външен ключ, когато командата актуализира колона с уникален ключ, която не е част от ключ за клъстериране и има един ред като източник на актуализацията в SQL Server 2008

Отнася се за
SQL Server 2008

Грешка #: 50003167 (SQL гореща корекция)

За повече информация относно главния списък с компилациите, които са издадени след издаването на SQL, щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

957826 Къде можете да намерите повече информация за компилациите на SQL Server 2008, които са издадени след SQL Server 2008 г., и компилациите на SQL Server 2005, които са издадени след SQL Server 2005 Service Pack 2

Симптоми

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

  • Издава се команда MERGE.
  • Целевата колона на актуализацията има неклъстериран уникален индекс.

Обмислете сценария, описан по-долу. Командата актуализира уникална колона, която е наречена "Колона1 " на таблица, която е наречена "Таблица1". Таблица1 е свързана с ограничение с външен ключ от таблица, която е наречена Таблица2.

Резултатът е, че редовете в Таблица1 се променят, когато не е трябвало да се променят. Освен това Таблица2 ще има редове, които имат висящи препратки към Таблица1.

Проблемът възниква за този сценарий, когато са налице следните условия:

  • Колоната " Колона1 ", към която има препратка в "Таблица1 ", не е част от ключа за клъстериране на "Таблица1".

  • За колоната "Колона1 " може да се присвои само една възможна стойност. Възниква например един от следните сценарии:

    • Източникът на обединяването е един ред с данни. Например източникът на обединяването е от една от следните команди за избиране:

      • select <ConstantValues>
        
      • select <Parameters>
        

      Обърнете внимание, че този сценарий е най-често срещаният.

    • Източникът на обединяването всъщност е един ред с данни. Например източникът на обединяването е от една от следните команди за избиране:

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

        Обърнете внимание <на TableName>.<ColumnName> е известно на оптимизатора на заявките като уникална стойност.

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

    • Клаузата update задава колоната Column1 на константна стойност, независимо от източника на обединяването.

  • Опцията При актуализиране каскадно не е разрешена за ограничението на външния ключ в Table2.

Забележка: Препоръчваме да приложите тази гореща корекция, ако използвате командата MERGE за актуализиране на колони, които имат неклъстерни уникални индекси, използвани от ограничения на външни ключове.

Решение

Корекцията за този проблем е издадена за първи път в кумулативна актуализация 1. За допълнителна информация как да получите този сборен пакет за актуализация за SQL Server 2008, щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

956717 Сборен пакет за актуализация 1 за SQL Server 2008

Забележка: Тъй като компилациите са кумулативни, всяка нова корекция съдържа всички актуални поправки и корекции на защитата, които са били включени в предишното издание на корекция на SQL Server 2008. Препоръчваме ви да помислите за прилагане на най-новото издание на корекцията, което съдържа тази гореща корекция. За допълнителна информация щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

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 потвърждава, че това е проблем в продуктите на Microsoft, които са изброени в раздела „Важи за“.

Повече информация

За повече информация относно това какви файлове са променени и за информация за всички предварителни условия за прилагане на кумулативния пакет за актуализация, който съдържа актуалната корекция, описана в тази статия от базата знания на Microsoft, щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

956717 Сборен пакет за актуализация 1 за SQL Server 2008

Справки

За повече информация относно списъка с компилациите, които са налични след издаването на SQL Server 2008, щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

956909 Компилациите на SQL Server 2008, които са издадени след издаването на SQL Server 2008

За повече информация относно модела на постъпково обслужване за SQL Server щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

935897 От екипа на SQL Server се предлага модел на постъпково обслужване, който да предоставя актуални корекции за съобщени проблеми

За допълнителна информация относно схемата за именуване на актуализациите на SQL Server щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

822499 Нова схема за именуване на пакетите за актуализация на софтуера на Microsoft SQL Server

За допълнителна информация относно терминологията относно софтуерните актуализации щракнете върху следния номер на статия, за да прегледате статията в базата знания на Microsoft:

824684 Описание на стандартната терминология, която се използва за описание на софтуерните актуализации на Microsoft

Неклъстерни индекси в SQL Server 2008

За повече информация за неклъстерните индекси в SQL Server 2008 посетете следния уеб сайт на Microsoft Developer Network (MSDN):

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