KB956718 - CORREZIONE: un'istruzione MERGE potrebbe non applicare un vincolo di chiave esterna quando l'istruzione aggiorna una colonna di chiave univoca che non fa parte di una chiave di clustering ed è presente una singola riga come origine di aggiornamento in SQL Server 2008

Si applica a
SQL Server 2008

Bug #: 50003167 (aggiornamento rapido SQL)

Per ulteriori informazioni sull'elenco principale delle build rilasciate dopo il rilascio di SQL, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:

957826 Dove è possibile trovare altre informazioni sulle build SQL Server 2008 rilasciate dopo SQL Server 2008 e sulle build SQL Server 2005 rilasciate dopo SQL Server Service Pack 2 2005

Sintomi

In Microsoft SQL Server 2008, un vincolo di chiave esterna potrebbe non essere applicato quando si verificano le condizioni seguenti:

  • Viene emessa un'istruzione MERGE.
  • La colonna di destinazione dell'aggiornamento contiene un indice univoco non cluster.

Si consideri lo scenario seguente. L'istruzione aggiorna una colonna univoca denominata Column1 di una tabella denominata Table1. Table1 è referenziato da un vincolo di chiave esterna di una tabella denominata Table2.

Il risultato è che le righe della Tabella1 vengono modificate quando non avrebbero dovuto esserlo. Inoltre, la Tabella2 avrà righe con riferimenti penzolanti a Tabella1.

Questo problema si verifica in questo scenario quando si verificano le condizioni seguenti:

  • La colonna Column1 a cui si fa riferimento in Table1 non fa parte della chiave di clustering di Table1.

  • Alla colonna Column1 può essere assegnato un solo valore possibile. Si verifica ad esempio uno degli scenari seguenti:

    • L'origine di unione è una singola riga di dati. Ad esempio, l'origine dell'unione proviene da una delle istruzioni select seguenti:

      • select <ConstantValues>
        
      • select <Parameters>
        

      Nota: questo scenario è il più probabile.

    • L'origine di unione è in realtà una singola riga di dati. Ad esempio, l'origine dell'unione proviene da una delle istruzioni select seguenti:

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

        Nota <TableName>.<ColumnName> è noto a Query Optimizer come valore univoco.

      • select top 1 <ColumnName> from <TableName>
        
    • Il join tra l'origine e la destinazione di unione ha un predicato che garantisce l'aggiornamento di una singola riga.

    • La clausola di aggiornamento imposta la colonna Column1 su un valore costante, indipendentemente dall'origine di unione.

  • L'opzione Su aggiornamento a catena non è abilitata nel vincolo di chiave esterna nella Tabella 2.

Nota: si consiglia di applicare questo aggiornamento rapido se si utilizza l'istruzione MERGE per aggiornare le colonne con indici univoci non cluster a cui fanno riferimento vincoli di chiave esterna.

Risoluzione

La correzione di questo errore è stata rilasciata per la prima volta nell'aggiornamento cumulativo 1. Per ulteriori informazioni su come ottenere questo pacchetto di aggiornamento cumulativo per SQL Server 2008, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:

956717 Pacchetto di aggiornamento cumulativo 1 per SQL Server 2008

Nota: poiché le build sono cumulative, ogni nuova versione di correzione contiene tutte le correzioni rapide e di sicurezza incluse nella versione precedente di correzione di SQL Server 2008. Si consiglia di applicare l'ultima versione della correzione che contiene questo aggiornamento rapido (hotfix). Per ulteriori informazioni, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:

956909 Le SQL Server build 2008 rilasciate dopo SQL Server 2008

Soluzione alternativa

Il pacchetto di hotfix elimina il problema. Se si usa l'istruzione MERGE nello scenario descritto nella sezione "Sintomi" e se si sceglie di non applicare l'hotfix, seguire questa procedura per eliminare il problema:

  1. Riscrivere l'istruzione MERGE in modo che i valori per l'origine di unione si trovino in una tabella, in una tabella temporanea o in una variabile di tabella anziché essere inline nella query.

  2. Usa il flag di traccia 8790. Questo flag di traccia forza l'utilità di ottimizzazione a usare un tipo di piano denominato piano di aggiornamento ampio. I piani di aggiornamento su larga scala non hanno il problema. Questo passaggio comporta rischi di prestazioni per tutte le istruzioni DML. Pertanto, è consigliabile evitare di usare questo passaggio a meno che non sia impossibile modificare l'applicazione.

Lo script Transact-SQL seguente mostra un modo per modificare lo script per risolvere il problema se non è possibile applicare questo aggiornamento rapido (hotfix).

Ad esempio, si dispone di uno script simile al seguente:

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);

Modificare lo script in modo che sia simile al seguente:

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);

Stato

Microsoft ha confermato che si tratta di un problema relativo ai prodotti elencati nella sezione "Si applica a".

Altre informazioni

Per ulteriori informazioni sui file modificati e sui prerequisiti per l'applicazione del pacchetto di aggiornamento cumulativo contenente l'aggiornamento rapido descritto in questo articolo della Microsoft Knowledge Base, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:

956717 Pacchetto di aggiornamento cumulativo 1 per SQL Server 2008

Riferimenti

Per ulteriori informazioni sull'elenco delle build disponibili dopo il rilascio di SQL Server 2008, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:

956909 Le SQL Server build 2008 rilasciate dopo SQL Server 2008

Per ulteriori informazioni sul modello di servizio incrementale per SQL Server, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:

935897 un modello di manutenzione incrementale è disponibile dal team SQL Server per fornire correzioni rapide per i problemi segnalati

Per ulteriori informazioni sullo schema di denominazione per gli aggiornamenti di SQL Server, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:

822499 Nuovo schema di denominazione per i pacchetti di aggiornamento software Microsoft SQL Server

Per ulteriori informazioni sulla terminologia degli aggiornamenti software, fare clic sul numero dell'articolo della Microsoft Knowledge Base riportato di seguito:

824684 Descrizione della terminologia standard utilizzata per descrivere gli aggiornamenti software Microsoft

Indici non cluster in SQL Server 2008

Per ulteriori informazioni sugli indici non cluster in SQL Server 2008, visitare il seguente sito Web Microsoft Developer Network (MSDN):

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