Aggiunto il 7/11 Il problema è che si verificano deadlock a causa della scansione dell'indice durante MERGE JOIN. In questo caso una transazione che tenta di ottenere il blocco S sull'intero indice nella tabella padre FK, ma in precedenza un'altra transazione inserisce il blocco X su un valore chiave dell'indice.
Vorrei iniziare con un piccolo esempio (utilizzato TSQL2012 DB da 70-461 Cource):
CREATE TABLE [Sales].[Orders](
[orderid] [int] IDENTITY(1,1) NOT NULL,
[custid] [int] NULL,
[empid] [int] NOT NULL,
[shipperid] [int] NOT NULL,
... )
Le colonne [custid], [empid], [shipperid]
sono parametri corelati di [Sales].[Customers], [HR].[Employees], [Sales].[Shippers]
conseguenza. In ogni caso abbiamo un indice cluster su una colonna di riferimento in una tabella parrent.
ALTER TABLE [Sales].[Orders] WITH CHECK ADD CONSTRAINT [FK_Orders_Customers] FOREIGN KEY([custid]) REFERENCES [Sales].[Customers] ([custid])
ALTER TABLE [Sales].[Orders] WITH CHECK ADD CONSTRAINT [FK_Orders_Employees] FOREIGN KEY([empid]) REFERENCES [HR].[Employees] ([empid])
ALTER TABLE [Sales].[Orders] WITH CHECK ADD CONSTRAINT [FK_Orders_Shippers] FOREIGN KEY([shipperid])REFERENCES [Sales].[Shippers] ([shipperid])
Sto provando ad INSERT [Sales].[Orders] SELECT ... FROM
un altro tavolo chiamato [Sales].[OrdersCache]
che ha la stessa struttura [Sales].[Orders]
delle chiavi esterne tranne. Un'altra cosa potrebbe essere importante menzionare la tabella [Sales].[OrdersCache]
è un indice cluster.
CREATE CLUSTERED INDEX idx_c_OrdersCache ON Sales.OrdersCache ( custid, empid )
Come previsto, quando sto cercando di inserire un volume ridotto di dati, LOOP JOIN funziona bene facendo cercare l'indice sulle chiavi esterne.
Con elevati volumi di dati MERGE JOIN viene utilizzato da Query Optimizer come un modo più efficiente per mantenere la chiave foregn nella query.
E non c'è nulla a che fare con questo, tranne OPTION (LOOP JOIN) nel nostro caso con chiavi esterne o INNER LOOP JOIN nel caso esplicito JOIN.
Di seguito è la query che sto cercando di eseguire nel mio ambiente:
INSERT Sales.Orders (
custid, empid, shipperid, ... )
SELECT custid, empid, 2, ...
FROM Sales.OrdersCache
Osservando il piano, possiamo vedere che tutte e 3 le chiavi di inserimento sono state validate con MERGE JOIN. Per me non è un modo appropriato poiché utilizza SCANSIONE INDICE con blocco dell'intero indice.
L'uso di OPTION (LOOP JOIN) non è adatto poiché costa quasi il 15% in più rispetto a MERGE JOIN (penso che la regressione sarà maggiore con l'aumento dei volumi di dati).
Nell'istruzione SELECT è possibile visualizzare un valore singolo per l' shipperid
attributo per l'intero set inserito. A mio avviso, ci deve essere un modo per accelerare la fase di convalida per l'insieme inserito almeno per l'attributo immutabile. Qualcosa di simile a:
- crea LOOP JOIN, MERGE JOIN, HASH JOIN se abbiamo un sottoinsieme indefinito per la validazione JOIN
- se esiste un solo valore esplicito della colonna convalidata, effettuiamo la convalida una sola volta (INDICE SEEK).
Esiste un modello comune per superare la situazione precedente utilizzando strutture di codice, oggetti DDL aggiuntivi, ecc.?
Aggiunto il 20/07. Soluzione. Query Optimizer effettua già un'ottimizzazione di convalida "chiave singola - chiave esterna" utilizzando MERGE JOIN. E rende solo per la tabella Sales.Shippers, lasciando LOOP JOIN per altri join nella query contemporaneamente. Dal momento che ho alcune righe nella tabella padre, lo Strumento per ottimizzare le query utilizza l'algoritmo di join Ordinamento-unione e confronta ogni riga della tabella interna con la tabella padre una sola volta. Questa è la risposta alla mia domanda se esiste un meccanismo particolare per elaborare efficacemente singoli valori in un set durante la convalida della chiave singola. Non è una decisione così perfetta, ma è così che SQL Server ottimizza il caso.
L'indagine sull'incidenza delle prestazioni ha rivelato che nel mio caso le istruzioni di inserimento MERGE JOIN e LOOP JOIN sono diventate approssimativamente uguali con 750 righe inserite simultaneamente con la seguente superiorità di MERGE JOIN (nella risorsa tempo CPU). Quindi l'utilizzo di OPTION (LOOP JOIN) è una soluzione appropriata per il mio processo aziendale.