Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Bergabung dengan Eliminasi:Ketika SQL Server Menghapus Tabel yang Tidak Perlu

Penulis Tamu :Bert Wagner (@bertwagner)

Penghapusan gabungan adalah salah satu dari banyak teknik yang digunakan pengoptimal kueri SQL Server untuk membuat rencana kueri yang efisien. Secara khusus, penghapusan gabungan terjadi ketika SQL Server dapat menetapkan kesetaraan dengan menggunakan logika kueri atau batasan basis data tepercaya untuk menghilangkan gabungan yang tidak perlu. Lihat versi video lengkap dari postingan ini di saluran YouTube saya.

Bergabung dalam Tindakan Eliminasi

Cara paling sederhana untuk menjelaskan eliminasi bergabung adalah melalui serangkaian demo. Untuk contoh ini saya akan menggunakan database demo WideWorldImporters.

Untuk memulai, kita akan melihat cara kerja eliminasi gabungan saat kunci asing ada:

PILIH il.* FROM Sales.InvoiceLines il INNER JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID;

Dalam contoh ini, kami hanya mengembalikan data dari Sales.InvoiceLines di mana InvoiceID yang cocok ditemukan di Sales.Invoices. Meskipun Anda mungkin mengharapkan rencana eksekusi untuk menampilkan operator gabungan pada tabel Sales.InvoiceLines dan Sales.Invoices, SQL Server tidak pernah repot-repot melihat Sales.Invoices sama sekali:

SQL Server menghindari bergabung ke tabel Sales.Invoices karena mempercayai integritas referensial yang dipertahankan oleh batasan kunci asing yang ditentukan pada InvoiceID antara Sales.InvoiceLines dan Sales.Invoices; jika ada baris di Sales.InvoiceLines, baris dengan nilai yang cocok untuk InvoiceID harus ada di Sales.Faktur. Dan karena kami hanya mengembalikan data dari tabel Sales.InvoiceLines, SQL Server tidak perlu membaca halaman apa pun dari Sales.Invoices sama sekali.

Kami dapat memverifikasi bahwa SQL Server menggunakan batasan kunci asing untuk menghilangkan gabungan dengan menghapus batasan dan menjalankan kueri kami lagi:

ALTER TABLE [Penjualan].[InvoiceLines] DROP CONSTRAINT [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];

Tanpa informasi tentang hubungan antara dua tabel kami, SQL Server dipaksa untuk melakukan penggabungan, memindai indeks pada tabel Sales.Invoices kami untuk menemukan InvoiceIDs yang cocok.

Dari sudut pandang I/O, SQL Server harus membaca 124 halaman tambahan dari indeks pada tabel Sales.Invoices, dan itu hanya karena SQL Server dapat menggunakan indeks sempit (kolom tunggal) yang dibuat oleh batasan kunci asing yang berbeda. Skenario ini bisa menjadi jauh lebih buruk pada tabel yang lebih besar atau tabel yang tidak diindeks dengan tepat.

Batasan

Sementara contoh sebelumnya menunjukkan dasar-dasar cara kerja eliminasi gabungan, kita perlu menyadari beberapa peringatan.

Pertama, mari tambahkan kembali batasan kunci asing kita:

ALTER TABLE [Penjualan].[InvoiceLines] WITH NOCHECK ADD CONSTRAINT [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices] FOREIGN KEY([InvoiceID])REFERENSI [Penjualan].[Faktur] ([InvoiceID]);

Jika kami menjalankan kueri sampel kami lagi, kami akan melihat bahwa kami tidak mendapatkan paket yang menunjukkan penghapusan gabungan; sebagai gantinya kami mendapatkan paket yang memindai kedua tabel yang kami gabungkan.

Alasan ini terjadi karena, ketika kami menambahkan kembali batasan kunci asing kami, SQL Server tidak tahu apakah ada data yang telah dimodifikasi sementara itu. Data baru atau yang diubah mungkin tidak mematuhi batasan ini, jadi SQL Server tidak dapat mempercayai validitas data kami:

PILIH f.name AS foreign_key_name ,OBJECT_NAME(f.parent_object_id) AS table_name ,COL_NAME(fc.parent_object_id, fc.parent_column_id) AS constraint_column_name ,OBJECT_NAME (f.referenced_object_id) AS referenced_reference_object ) AS referenced_column_name ,f.is_not_trustedFROM sys.foreign_keys AS f INNER JOIN sys.foreign_key_columns AS fc ON f.object_id =fc.constraint_object_idWHERE f.parent_object_id =OBJECT_ID('Sales');

Untuk membangun kembali kepercayaan SQL Server terhadap batasan ini, kita harus memeriksa validitasnya:

ALTER TABLE [Penjualan].[InvoiceLines] DENGAN KONSTRAIN CEK CEK [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];

Pada tabel besar, operasi ini mungkin memakan waktu, belum lagi overhead SQL Server yang memvalidasi data ini selama setiap modifikasi penyisipan/pembaruan/penghapusan yang akan datang.

Keterbatasan lain adalah bahwa SQL Server tidak dapat menghilangkan tabel yang digabungkan ketika kueri perlu mengembalikan data apa pun dari kandidat eliminasi potensial tersebut:

PILIH il.*, i.InvoiceDateFROM Sales.InvoiceLines il INNER JOIN Sales.Faktur i PADA il.InvoiceID =i.InvoiceID;

Penghapusan gabungan tidak terjadi dalam kueri di atas karena kami meminta data dari Penjualan. Faktur dikembalikan, memaksa SQL Server untuk membaca data dari tabel itu.

Terakhir, penting untuk dicatat bahwa eliminasi gabungan tidak akan terjadi ketika kunci asing memiliki banyak kolom, atau jika tabel dalam tempdb. Yang terakhir adalah salah satu dari beberapa alasan Anda tidak boleh mencoba memecahkan masalah pengoptimalan dengan menyalin tabel Anda ke tempdb.

Skenario Tambahan

Beberapa Tabel

Penghapusan gabungan tidak hanya terbatas pada gabungan dalam dua tabel dan tabel dengan batasan kunci asing.

Misalnya, kita dapat membuat tabel tambahan yang mereferensikan kolom Sales.Invoices.InvoiceID:

BUAT TABEL Sales.InvoiceClickTracking ( InvoiceClickTrackingID bigint IDENTITY PRIMARY KEY, InvoiceID int -- bidang lain akan dimasukkan ke sini ); PERGI ALTER TABLE [Penjualan].[InvoiceClickTracking] WITH CHECK ADD CONSTRAINT [FK_Sales_InvoiceClickTracking_InvoiceID_Sales_Invoices] FOREIGN KEY([InvoiceID]) REFERENSI [Penjualan].[Faktur] ([InvoiceID]);

Bergabung dengan tabel ini ke dalam kueri sampel asli kami juga akan memungkinkan SQL Server untuk menghilangkan tabel Sales.Invoices kami:

PILIH il.InvoiceID, ict.InvoiceID FROM Sales.InvoiceLines il INNER JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID INNER JOIN Sales.InvoiceClickTracking ict ON i.InvoiceID =ict.InvoiceID;

SQL Server dapat menghilangkan tabel Sales.Invoices karena hubungan transitif antara hubungan tabel ini.

Batasan Unik

Alih-alih batasan kunci asing, SQL Server juga akan melakukan penghapusan gabungan jika dapat mempercayai hubungan data dengan batasan unik:

ALTER TABLE [Penjualan].[InvoiceClickTracking] DROP CONSTRAINT [FK_Sales_InvoiceClickTracking_InvoiceID_Sales_Invoices]; GO ALTER TABLE Penjualan.InvoiceClickTracking ADD CONSTRAINT UQ_InvoiceID UNIQUE (InvoiceID); PERGI PILIH i.InvoiceID DARI Penjualan.InvoiceClickTracking ict RIGHT JOIN Sales.Invoices i ON ict.InvoiceID =i.InvoiceID;

Gabungan Luar

Selama SQL Server dapat menyimpulkan batasan hubungan, jenis gabungan lainnya juga dapat mengalami penghapusan tabel. Misalnya:

PILIH il.InvoiceIDFROM Sales.InvoiceLines il LEFT JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID

Karena kami masih memiliki batasan kunci asing yang memaksa bahwa setiap InvoiceID di Sales.InvoiceLines harus memiliki InvoiceID yang sesuai di Sales.Invoices, SQL Server tidak memiliki masalah untuk mengembalikan semuanya dari Sales.InvoiceLInes tanpa perlu bergabung ke Sales.Invoices:

Tidak Perlu Batasan

Jika SQL Server dapat menjamin bahwa itu tidak memerlukan data dari tabel tertentu, itu berpotensi menghilangkan bergabung.

Tidak ada penghapusan gabungan yang terjadi dalam kueri ini karena SQL Server tidak dapat mengidentifikasi apakah hubungan antara Sales.Invoices dan Sales.InvoiceLines adalah 1-ke-1, 1-ke-0, atau 1-ke-banyak. Itu dipaksa untuk membaca Sales.InvoiceLines untuk menentukan apakah ada baris yang cocok ditemukan:

PILIH i.InvoiceIDFROM Sales.InvoiceLines il RIGHT JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID;

Namun, jika kita menentukan bahwa kita menginginkan kumpulan i.InvoiceIDs yang BERBEDA, setiap nilai unik dari Sales.Invoices akan dikembalikan dari SQL Server terlepas dari hubungan apa yang dimiliki baris tersebut dengan Sales.InvoiceLines.

-- Hanya untuk membuktikan tidak ada kunci asing yang berperan di sini ALTER TABLE [Penjualan].[InvoiceLines] DROP CONSTRAINT [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices];GO -- Hasil kami yang berbeda setSELECT DISTINCT i.InvoiceIDFROM Sales.InvoiceLines il RIGHT GABUNG Penjualan.Invoice i ON il.InvoiceID =i.InvoiceID;

Tampilan

Salah satu keuntungan eliminasi gabungan adalah dapat bekerja dengan tampilan, meskipun kueri tampilan yang mendasarinya tidak dapat menggunakan eliminasi gabungan:

-- Tambahkan kembali FK ALTER TABLE [Penjualan].[InvoiceLines] WITH CHECK ADD CONSTRAINT [FK_Sales_InvoiceLines_InvoiceID_Sales_Invoices] FOREIGN KEY([InvoiceID])REFERENCES [Penjualan].[Faktur] ([InvoiceID]);PERGI -- Buat tampilan kami menggunakan kueri yang tidak dapat menggunakan join removalCREATE VIEW Sales.vInvoicesAndInvoiceLinesAS SELECT i.InvoiceID, i.InvoiceDate, il.Quantity, il.TaxRate FROM Sales.InvoiceLines il INNER JOIN Sales.Invoices i ON il.InvoiceID =i.InvoiceID; GO -- Penghapusan gabungan berfungsi karena kami tidak memilih -- kolom apa pun dari tabel Sales.Invoices yang mendasari SELECT Quantity, TaxRate FROM Sales.vInvoicesAndInvoiceLines;

Kesimpulan

Penghapusan gabungan adalah pengoptimalan yang dilakukan SQL Server ketika ditentukan bahwa itu dapat memberikan kumpulan hasil yang akurat tanpa perlu membaca data dari semua tabel yang ditentukan dalam kueri yang dikirimkan. Pengoptimalan ini dapat memberikan peningkatan kinerja yang signifikan dengan mengurangi jumlah halaman yang harus dibaca oleh SQL Server, namun sering kali harus mengorbankan kebutuhan untuk mempertahankan batasan basis data tertentu. Kami dapat memfaktorkan ulang kueri untuk mencapai rencana eksekusi yang lebih sederhana yang disediakan oleh penghapusan gabungan, namun memiliki pengoptimal kueri secara otomatis menyederhanakan rencana kami dengan menghapus gabungan yang tidak perlu adalah keuntungan yang bagus.

Sekali lagi, saya mengundang Anda untuk menonton versi video lengkap dari postingan ini.

Tentang Penulis

Bert adalah pengembang intelijen bisnis dari Cleveland, Ohio. Dia suka menulis kueri yang berjalan cepat dan senang membantu orang lain belajar menjadi pemecah masalah SQL mandiri. Bert membuat blog tentang SQL Server di bertwagner.com dan membuat video YouTube SQL Server di youtube.com/c/bertwagner.

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Ketahui Cara Memulihkan Tabel yang Dihapus di SQL Server 2012 Tanpa Cadangan

  2. Bagaimana Saya Menyisipkan Byte[] Ke dalam Kolom VARBINARY SQL Server

  3. Karakter Escape di SQL Server

  4. Daftar Tipe Data di SQL Server 2017

  5. Menggunakan StringWriter untuk Serialisasi XML