Bergabung sendiri pada kunci utama

9

Pertimbangkan permintaan ini yang terdiri dari Ngabungan-sendiri:

select
    t1.*
from [Table] as t1
join [Table] as t2 on
    t1.Id = t2.Id
-- ...
join [Table] as tN on
    t1.Id = tN.Id

Ini menghasilkan rencana eksekusi dengan N scan indeks berkerumun dan gabungan bergabung N-1.

Jujur, saya tidak melihat alasan untuk tidak mengoptimalkan semua bergabung dan melakukan hanya satu scan indeks berkerumun, yaitu mengoptimalkan permintaan asli untuk ini:

select
    t1.*
from [Table] as t1

Pertanyaan

  • Mengapa bergabung tidak dioptimalkan?
  • Apakah secara matematis salah untuk mengatakan bahwa setiap gabungan tidak mengubah hasil yang ditetapkan?

Diuji pada:

  • Versi Server Sumber: SQL Server 2014 (12.0.4213)
  • Sumber Database Engine Edition: Microsoft SQL Server Edisi Standar
  • Sumber Tipe Basis Data Mesin: Standalone SQL Server
  • Tingkat kompatibilitas: SQL Server 2008 (100)

Permintaan tidak bermakna; itu muncul di benak saya dan saya ingin tahu tentang hal itu sekarang.

Inilah biola dengan pembuatan tabel dan 3 kueri: dengan inner join, dengan left join, dan dicampur. Anda juga dapat melihat rencana eksekusi di sana juga.

Tampaknya left joins dihilangkan dalam rencana eksekusi hasil sementara inner joins tidak. Masih tidak mengerti mengapa .

pkuderov
sumber

Jawaban:

18

Pertama, mari kita asumsikan bahwa itu (id)adalah kunci utama tabel. Dalam hal ini, ya, gabungannya (dapat dibuktikan) berlebihan dan dapat dihilangkan.

Nah, itu hanya teori - atau matematika. Agar pengoptimal melakukan eliminasi aktual, teorinya harus dikonversi menjadi kode dan ditambahkan dalam rangkaian optimisasi / penulisan ulang / eliminasi. Agar itu terjadi, para pengembang (DBMS) harus berpikir bahwa itu akan memiliki manfaat yang baik untuk efisiensi dan itu adalah kasus yang cukup umum.

Secara pribadi, itu tidak terdengar seperti satu (cukup umum). Kueri - seperti yang Anda akui - terlihat agak konyol dan peninjau tidak boleh membiarkannya lolos ulasan, kecuali jika diperbaiki dan gabung yang berlebihan dihapus.

Yang mengatakan, ada pertanyaan serupa di mana eliminasi tidak terjadi. Ada posting blog terkait sangat bagus oleh Rob Farley: BERGABUNG penyederhanaan dalam SQL Server .

Dalam kasus kami, yang harus kami lakukan adalah mengubah gabung menjadi LEFTgabung. Lihat dbfiddle.uk . Pengoptimal dalam hal ini tahu bahwa gabungan dapat dihapus dengan aman tanpa mungkin mengubah hasilnya. (Logika penyederhanaan cukup umum dan tidak khusus untuk bergabung sendiri.)

Dalam kueri asli tentu saja, menghapus INNERgabungan tidak mungkin mengubah hasil juga. Tetapi sama sekali tidak umum untuk bergabung sendiri pada kunci utama sehingga optimizer tidak menerapkan kasus ini. Namun umum untuk bergabung (atau bergabung kiri) di mana kolom bergabung adalah kunci utama dari salah satu tabel (dan sering ada batasan kunci asing). Yang mengarah ke opsi kedua untuk menghilangkan gabungan: Tambahkan batasan kunci asing (referensi sendiri!):

ALTER TABLE "Table"
    ADD FOREIGN KEY (id) REFERENCES "Table" (id) ;

Dan voila, gabungannya dihilangkan! (Diuji dalam biola yang sama): di sini

create table docs
(id int identity primary key,
 doc varchar(64)
) ;
GO
insert
into docs (doc)
values ('Enter one batch per field, don''t use ''GO''')
     , ('Fields grow as you type')
     , ('Use the [+] buttons to add more')
     , ('See examples below for advanced usage')
  ;
GO
4 baris terpengaruh
--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    join docs d2 on d2.id=d1.id
    join docs d3 on d3.id=d1.id
    join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | dokter                                      
-: | : ----------------------------------------
 1 | Masukkan satu batch per bidang, jangan gunakan 'GO'
 2 | Bidang tumbuh saat Anda mengetik                  
 3 | Gunakan tombol [+] untuk menambahkan lebih banyak          
 4 | Lihat contoh di bawah ini untuk penggunaan lanjutan    

masukkan deskripsi gambar di sini

--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    left join docs d2 on d2.id=d1.id
    left join docs d3 on d3.id=d1.id
    left join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | dokter                                      
-: | : ----------------------------------------
 1 | Masukkan satu batch per bidang, jangan gunakan 'GO'
 2 | Bidang tumbuh saat Anda mengetik                  
 3 | Gunakan tombol [+] untuk menambahkan lebih banyak          
 4 | Lihat contoh di bawah ini untuk penggunaan lanjutan    

masukkan deskripsi gambar di sini

alter table docs
  add foreign key (id) references docs (id) ;
GO
--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;
select d1.* from docs d1 
    join docs d2 on d2.id=d1.id
    join docs d3 on d3.id=d1.id
    join docs d4 on d4.id=d1.id;
set statistics xml off;
GO
id | dokter                                      
-: | : ----------------------------------------
 1 | Masukkan satu batch per bidang, jangan gunakan 'GO'
 2 | Bidang tumbuh saat Anda mengetik                  
 3 | Gunakan tombol [+] untuk menambahkan lebih banyak          
 4 | Lihat contoh di bawah ini untuk penggunaan lanjutan    

masukkan deskripsi gambar di sini

ypercubeᵀᴹ
sumber
2

Dalam istilah relasional, siapa saja yang bergabung tanpa mengubah nama atribut adalah larangan dan dapat dengan aman dihilangkan dari rencana eksekusi. Sayangnya SQL tidak bersifat relasional dan situasi di mana self join dapat dihilangkan oleh optimizer terbatas pada sejumlah kecil kasus tepi.

Sintaks SELECT SQL memberikan bergabung diutamakan logis atas proyeksi. Aturan pelingkupan SQL untuk nama kolom dan fakta bahwa duplikat nama kolom dan kolom tanpa nama diizinkan membuat optimasi kueri SQL secara signifikan lebih sulit daripada optimasi aljabar relasional. SQL DBMS vendor memiliki sumber daya terbatas dan harus selektif tentang jenis optimasi yang ingin mereka dukung.

nvogel
sumber
1

Kunci utama selalu unik dan nilai nol tidak diizinkan sehingga bergabung dengan tabel itu sendiri pada kunci primer (tidak dengan kunci sekunder referensi sendiri dan tanpa pernyataan di mana) akan menghasilkan jumlah baris yang sama dengan tabel asli.

Mengenai mengapa mereka tidak mengoptimalkannya, saya akan mengatakan itu adalah kasus tepi yang mereka tidak rencanakan atau anggap orang tidak akan melakukannya. Bergabung dengan sebuah tabel untuk dirinya sendiri pada kunci utama dijamin unik tidak melayani tujuan.

indiri
sumber