Eklendi 7/11 Sorun, MERGE JOIN sırasında dizin taraması nedeniyle meydana gelmesi. Bu durumda, FK üst tablosundaki tüm dizinde S kilidi almaya çalışan bir işlem, ancak daha önce başka bir işlem X kilidini dizinin anahtar değerine koyar.
Küçük bir örnekle başlayayım (kullanılan 70-461 kurstan TSQL2012 DB):
CREATE TABLE [Sales].[Orders](
[orderid] [int] IDENTITY(1,1) NOT NULL,
[custid] [int] NULL,
[empid] [int] NOT NULL,
[shipperid] [int] NOT NULL,
... )
Sütunlar buna göre temel [custid], [empid], [shipperid]
parametrelerdir [Sales].[Customers], [HR].[Employees], [Sales].[Shippers]
. Her durumda, bir ayrıştırma tablosundaki belirtilen bir sütunda kümelenmiş bir dizin bulunur.
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])
Yabancı anahtarlar dışında aynı yapıya sahip INSERT [Sales].[Orders] SELECT ... FROM
denilen başka bir tabloya çalışıyorum . Tablonun kümelenmiş bir dizin olduğunu belirtmek başka bir şey olabilir .[Sales].[OrdersCache]
[Sales].[Orders]
[Sales].[OrdersCache]
CREATE CLUSTERED INDEX idx_c_OrdersCache ON Sales.OrdersCache ( custid, empid )
Beklendiği gibi düşük hacimli veri eklemeye çalıştığımda LOOP JOIN, yabancı anahtarlarda endeks araması yapıyor.
Yüksek hacimli verilerle MERGE JOIN, sorgu optimizer tarafından sorguda foregn anahtarını korumanın en etkili yolu olarak kullanılır.
Ve bizim durumumuzda yabancı anahtarlar ile OPTION (LOOP JOIN) veya açık JOIN durumunda INNER LOOP JOIN kullanılarak yapılan hiçbir şey yoktur.
Ortamımda çalıştırmaya çalıştığım sorgu aşağıdadır:
INSERT Sales.Orders (
custid, empid, shipperid, ... )
SELECT custid, empid, 2, ...
FROM Sales.OrdersCache
Plana baktığımızda, 3 yabancı anahtarın hepsinin MERGE JOIN ile doğrulandığını görebiliriz. İndeks kilitlemeli INDEX SCAN kullandığı için benim için uygun bir yol değil.
SEÇENEK (LOOP JOIN) kullanımı uygun değildir çünkü MERGE JOIN'den neredeyse% 15 daha fazladır (veri hacimlerinin artmasıyla gerileme daha büyük olacaktır).
SELECT deyiminde shipperid
, eklenen tüm kümenin özniteliği için tek bir değer görebilirsiniz . Kanımca, eklenen kümenin doğrulama aşamasını en azından değişmez öznitelik için daha hızlı yapmanın bir yolu olmalıdır. Gibi bir şey:
- JOIN doğrulaması için tanımlanmamış altkümemiz varsa LOOP JOIN, MERGE JOIN, HASH JOIN yap
- doğrulanmış sütunun yalnızca tek bir açık değeri varsa, doğrulamayı yalnızca bir kez yaparız (INDEX SEEK).
Kod yapılarını, ek DDL nesnelerini vb. Kullanarak yukarıdaki durumun üstesinden gelmek için ortak bir model var mı?
20/07 eklendi. Çözüm. Sorgu Optimize Edici, MERGE JOIN kullanarak zaten bir 'tek anahtar - yabancı anahtar' doğrulama optimizasyonu yapıyor. Ve sadece Sales.Shippers tablosu için yapar, LOOP JOIN'i aynı anda sorgudaki başka birleştirmeler için bırakır. Üst tabloda birkaç satır bulunduğundan Query Optimizer, Sort-merge join algoritmasını kullanır ve iç tablodaki her satırı üst tabloyla yalnızca bir kez karşılaştırır. Tek bir anahtar doğrulaması sırasında bir kümedeki tek değerleri etkin bir şekilde işlemek için herhangi bir mekanizma olup olmadığı sorumun cevabı budur. Bu mükemmel bir karar değil, SQL Server'ın davayı optimize etmesinin yolu bu.
Performans etkisi araştırması, benim durumumda MERGE JOIN ve LOOP JOIN insert ifadesinin, MERGE JOIN'in (CPU zaman kaynağında) aşağıdaki üstünlüğüne sahip 750 eşzamanlı olarak eklenen satırla yaklaşık olarak eşit olduğunu ortaya koydu. Bu yüzden OPTION (LOOP JOIN) kullanmak iş sürecim için uygun bir çözümdür.