SQL Server MERGE Komutu Kullanımı ve Performans Önerileri

SQL Server 2008 versiyonu ile birlikte hayatımıza giren MERGE komutu kullanılarak ayrı ayrı yapılabilen INSERT, UPDATE ve DELETE işlemleri artık tek bir komut ile gerçekleştirilebilmektedir. Özellikle iki tablo arasında veri senkronizasyonu sağlanması için gereken farklı DML işlemleri MERGE komutu ile tek seferde yapılabilmektedir. MERGE komutunun bir başka kullanımı ise veriambarı geliştirme kısmında gerçekleştirilen ETL süreçlerinin bir parçası olan Slowly Changing Dimensions (SCD) yapılarının MERGE kullanılarak tasarlanabilmesidir. Bu konuyu başka bir yazıda ele alacağız. Bu yazımızda SQL Server’da kullanılan MERGE komutunun genel kullanımını ele alacak ve performans optimizasyonu için nelere dikkat edilmesi gerektiği kısaca açıklayacağız.

Kullanılan sistemlerde bazen bir tablodaki verilerin düzenli aralıklarla başka bir tabloya verilerini taşımak ve her iki tabloyu senkron etmek gerekebilir. Bu bazen bir test ortamı ile production ortamı arasında ihtiyaç duyulabilen bir senaryo olabileceği gibi bazen de OLTP veritabanları ile veriambarı katmanı arasında bu gibi ihtiyaçlara gereksinim duyulabilmektedir. Örneğimizde EmployeeSource isminde bir kaynak tablomuzu ve aynı yapıya sahip EmployeeTarget isminde bir hedef tablomuzu kullanacağız. Bu iki tablonun scriptleri aşağıdaki gibidir:

create table EmployeeSource
(
EmployeeID int,
FirstName nvarchar(50),
LastName nvarchar(50),
Title nvarchar(100),
RecruitmentDate datetime,
Salary decimal,
IsActive bit
)
GO


create table EmployeeTarget
(
EmployeeID int,
FirstName nvarchar(50),
LastName nvarchar(50),
Title nvarchar(100),
RecruitmentDate datetime,
Salary decimal,
IsActive bit
)
GO

Bu iki tabloyu create ettikten sonra içine örneğimizi gerçekleştireceğimiz birkaç tane veri girişi yapalım:

insert into dbo.EmployeeTarget 
values
(1, N'Abdullah', N'Altıntaş', N'Takım Lideri', '20120721', 1000, 1),
(2, N'İsmail', N'Adar', N'DBA', '20090101', 1500, 1),
(3, N'Yusuf', N'Boğatepe', N'Danışman', '20140103', 1000, 1),
(4, N'Merve', N'Sağlam', N'Kıdemli Danışman', '20150618', 1800, 1)
GO

insert into dbo.EmployeeSource
values
(1, N'Abdullah', N'Altıntaş', N'Takım Lideri', '20120721', 2000, 1),
(2, N'İsmail', N'Adar', N'DBA', '20090101', 1500, 1),
(3, N'Yusuf', N'Boğatepe', N'Danışman', '20140103', 1000, 1),
(5, N'Şeydanur', N'Sandıkçı', N'Danışman', GETDATE(), 1000, 0)
GO

Ardından bu komutları da çalıştırdıktan sonra tablolarımız üzerindeki verileri kontrol edelim:

select * from dbo.EmployeeSource
select * from dbo.EmployeeTarget

Sorguyu çalıştırdığımızda verileri aldığımız kaynak tablomuzu temsil eden EmployeeSource tablosu ile verileri aktarmayı amaçladığımız (source tablosu ile senkron olmasını istediğimiz) hedef tablomuz EmployeeTarget tablosunda bazı verilerin farklı olduğunu görebilirsiniz. Örneğimizde 1 nolu id ye sahip Abdullah Altıntaş’ın kaynak tablodaki maaş bilgisi değişmiş ve 1000 yerine 2000 değerini almış, 2 ve 3 nolu id ye ait kayıtlarda herhangi bir değişiklik yapılmamıştır. Ayrıca kaynak tabloda hedef tablosunda henüz bulunmayan 5 nolu id ye sahip Şeydanur Sandıkçı eklenmiş olmakla beraber hedef tablosunda artık kaynak tabloda bulunmayan 4 nolu id ye sahip Merve Sağlam kaydı bulunmaktadır.

kaynak ve hedef Amacımız bu iki tablonun verilerini senkronize etmek olduğundan şu işlemleri yapmamız gerekmektedir;

  1. Kaynak tabloda olup hedef tabloda olmayan verileri insert etmek,
  2. Kaynak tabloda olup hedef tabloda da olan verileri olması muhtemel değişiklikleri uygulamak için update etmek,
  3. Hedef tabloda olup artık kaynak tabloda bulunmayan kayıtları delete etmek.

Bu işlemleri ayrı ayrı INSERT, UPDATE ve DELETE kullanarak yapabileceğimiz gibi SQL Server 2008 ile beraber gelen MERGE komutu ile tek seferde de gerçekleştirebiliriz. Şimdi beklenen değişiklikleri uygulayabilmek için gerekli olan kodu yazalım:

MERGE INTO dbo.EmployeeTarget as t
USING dbo.EmployeeSource as s
ON t.EmployeeID = s.EmployeeID
WHEN MATCHED THEN
	UPDATE SET t.FirstName = s.FirstName, 
				t.LastName = s.LastName, 
				t.Title = s.Title, 
				t.RecruitmentDate = s.RecruitmentDate,
				t.Salary = s.Salary,
				t.IsActive = s.IsActive
WHEN NOT MATCHED BY TARGET THEN
	INSERT (EmployeeID, FirstName, LastName, Title, RecruitmentDate, Salary, IsActive)
	VALUES (s.EmployeeID, s.FirstName, s.LastName, s.Title, s.RecruitmentDate, s.Salary, s.IsActive)
WHEN NOT MATCHED BY SOURCE THEN
	DELETE
OUTPUT $action as YapilanIslem, deleted.EmployeeID, inserted.EmployeeID;

Yazdığımız kod bloğunu isterseniz kısaca açıklayalım:

İlk olarak MERGE INTO komutu ile hedef tablomuzu belirttik. Ardından verileri hangi tablodan çekeceğimizi USING ifadesi ile belirledik. (Burada USING ifadesi ile sadece var olan tabloları değil view, CTE, derived table, udf vb kullanabilirsiniz.) Kaynak ve hedef tablolarındaki verilerin daha önceden olup olmadıklarını karşılaştırabilmek için unique olan EmployeeID kolonu üzerinden gerekli kontrolü gerçekleştirdik. Bu işlemin ardından;

  1. WHEN MATCHED THEN ifadesi ile hedefte daha önce bulunan ve kaynak tablosundaki muhtemel değişiklikleri uygulamamız için gerekli olan UPDATE komutu ile güncelleme yapılması,
  2. WHEN NOT MATCHED BY TARGET ifadesi ile hedefte henüz bulunmayan ama kaynak tablosunda bulunan ve hedef tablosuna eklenmesi gereken kayıtlar için INSERT komutu ile gerekli kayıtların eklenmesi,
  3. WHEN NOT MATCHED BY SOURCE ifadesi ile hedefte bulunan ancak kaynak tablosunda artık bulunmayan kayıtların silinmesi için (test verileri vb olabilir) DELETE komutu ile bu verilerin silinmesi sağlanmıştır.

Burada dikkat edilmesi gereken her 3 işlem için de (INSERT, UPDATE, DELETE) hangi tablo üzerinde bu komutların çalıştırılacağının yazılmamasıdır. MERGE komutu içinde bu işlemler otomatik olarak sadece hedef tablosunda yapılacaktır. Tablo ismini bu 3 komutun yanında kullanmamız durumunda syntax hatası alacağımızı belirtmek isterim. Ayrıca bir diğer ipucu olarak da WHEN NOT MATCHED BY TARGET komutu yerine kısaca  WHEN NOT MATCHED yazabileceğimizi de belirtmek isterim.

Kodun son kısmında OUTPUT seçeneği ile etkilenen kayıtlara ait bilgiler çıktı olarak ekranda sonuç setinde gösterilecektir. $action ifadesi MERGE içinde OUTPUT ile birlikte kullanılabilmekte ve yapılan işlemi (INSERT, UPDATE, DELETE) göstermektedir.

İlgili MERGE komutunu çalıştırdığımızda aşağıdaki sonuç karşımıza çıkacaktır:

Buradan da görüleceği üzere EmployeeSource tablosundaki 1, 2 ve 3 nolu kayıtlar UPDATE edilmiş, 5 nolu kayıt (daha önce hedefte olmadığı için) INSERT edilmiş, kaynakta NULL yazan kayıt (aslında hedefte 4 nolu kayıt) artık olmadığı için DELETE edilmiştir.

MERGE komutunu çalıştırdıktan sonra EmployeeSource ve EmployeeTarget tablolarını tekrar sorgulayıp sonucuna bakalım:

kaynak ve hedef2

Görüldüğü gibi her iki tablodaki kayıtlar artık tamamen birbirine eşit duruma gelmiştir.

  • MERGE – Performans İçin Dikkat Edilecek Noktalar

MERGE komutu kullanılmadan iki tablo birbirine senkron edilmek istenirse ayrı ayrı INSERT, UPDATE ve DELETE işlemleri gerçekleştirilecek ve tablodaki veriler 3 işlem için tekrar tekrar ele alınacaktır. MERGE ifadesi ile tablo tek seferde ele alınacağından bu 3 işlem tek seferde yapılacaktır. Bu da çoğu durumda bize performans kazanımı sağlamaktadır. Yine de MERGE komutunun performanslı bir şekilde çalışmasını sağlamak için dikkat edilmesi gereken bazı noktalar vardır. Bunlardan başlıca bir kaç tanesini burada belirtelim;

  1. Kaynak ve hedef tabloları joinleyeceğimiz kolonlar üzerinde uygun indexlerin oluşturulması,
  2. Eğer verileri üzerinde bir filtre verilmek isteniyorsa bunun ON ifadesinde değil uygun eşleştirme kısmında (WHEN MATCHED ya da NOT MATCHED) ele alınması,
  3. Bir veri dosyasından OPENROWSET ile veri çekilirken uygun indexlerin oluşturulmasının yanı sıra OPENROWSET ifadesi ile birlikte ORDER ve UNIQUE bileşenlerinin verilmesi performansa olumlu katkı yapacaktır.

MERGE komutunun performanslı bir şekilde çalışmasını sağlayabilmek için nelere dikkat edilmesi gerektiğine aşağıdaki linkten daha detaylı olarak ulaşabilirsiniz;

https://technet.microsoft.com/en-us/library/cc879317.aspx

Bu yazımızda genel olarak SQL Server’da MERGE komutunun nasıl kullanılabileceğini ele aldık. Örnek bir uygulama ile iki tablo üzerindeki verilerin senkron edilmesini sağladık. Başka bir yazımızda MERGE komutu kullanılarak SCD type 1 ve SCD type 2 işlemlerinin nasıl yapılabileceğini ele alacağız. Umarım faydalı olur. Keyifli okumalar…

Yazar: Abdullah ALTINTAŞ

SQL Server MERGE Komutu Kullanımı ve Performans Önerileri” üzerine 2 düşünce

Yorum Yaz