Saya mencoba untuk menghasilkan contoh rencana kueri untuk menunjukkan mengapa UNION menggunakan dua set hasil dapat lebih baik daripada menggunakan ATAU dalam klausa GABUNG. Paket permintaan yang saya tulis membuat saya bingung. Saya menggunakan database StackOverflow dengan indeks nonclustered pada Users.Reputation.
CREATE NONCLUSTERED INDEX IX_NC_REPUTATION ON dbo.USERS(Reputation)
SELECT DISTINCT Users.Id
FROM dbo.Users
INNER JOIN dbo.Posts
ON Users.Id = Posts.OwnerUserId
OR Users.Id = Posts.LastEditorUserId
WHERE Users.Reputation = 5
Rencana kueri ada di https://www.brentozar.com/pastetheplan/?id=BkpZU1MZE , durasi kueri untuk saya adalah 4:37 menit, 26612 baris dikembalikan.
Saya belum pernah melihat gaya pemindaian konstan ini dibuat dari tabel yang ada sebelumnya - Saya tidak terbiasa dengan mengapa ada pemindaian konstan dijalankan untuk setiap baris, ketika pemindaian konstan biasanya digunakan untuk satu baris yang dimasukkan oleh pengguna. misalnya SELECT GETDATE (). Mengapa ini digunakan di sini? Saya akan sangat menghargai beberapa panduan dalam membaca rencana permintaan ini.
Jika saya membagi ATAU menjadi UNION, itu menghasilkan rencana standar berjalan dalam 12 detik dengan 26612 baris yang sama dikembalikan.
SELECT Users.Id
FROM dbo.Users
INNER JOIN dbo.Posts
ON Users.Id = Posts.OwnerUserId
WHERE Users.Reputation = 5
UNION
SELECT Users.Id
FROM dbo.Users
INNER JOIN dbo.Posts
ON Users.Id = Posts.LastEditorUserId
WHERE Users.Reputation = 5
Saya menafsirkan rencana ini sebagai melakukan ini:
- Dapatkan semua 41782500 baris dari Posting (jumlah aktual baris cocok dengan pemindaian CI pada Posting)
- Untuk setiap 41782500 baris dalam Posting:
- Menghasilkan skalar:
- Expr1005: OwnerUserId
- Expr1006: OwnerUserId
- Expr1004: Nilai statis 62
- Expr1008: LastEditorUserId
- Expr1009: LastEditorUserId
- Expr1007: Nilai statis 62
- Dalam gabungan:
- Exp1010: Jika Expr1005 (OwnerUserId) bukan nol, gunakan yang lain gunakan Expr1008 (LastEditorUserID)
- Expr1011: Jika Expr1006 (OwnerUserId) bukan nol, gunakan itu, kalau tidak gunakan Expr1009 (LastEditorUserId)
- Expr1012: Jika Expr1004 (62) adalah null gunakan itu, kalau tidak gunakan Expr1007 (62)
- Dalam skalar Hitung: Saya tidak tahu apa yang dilakukan ampersand.
- Expr1013: 4 [dan?] 62 (Expr1012) = 4 dan OwnerUserId NULL (NULL = Expr1010)
- Expr1014: 4 [dan?] 62 (Expr1012)
- Expr1015: 16 dan 62 (Expr1012)
- Dalam Urutan Dengan mengurutkan berdasarkan:
- Expr1013 Desc
- Expr1014 Asc
- Expr1010 Asc
- Expr1015 Desc
- Dalam Gabung Interval dihapus Expr1013 dan Expr1015 (ini adalah input tetapi bukan output)
- Dalam pencarian Indeks di bawah loop bersarang bergabung itu menggunakan Expr1010 dan Expr1011 sebagai mencari predikat, tapi saya tidak mengerti bagaimana ia memiliki akses ke ini ketika belum melakukan loop bersarang bergabung dari IX_NC_REPUTATION ke subtree yang berisi Expr1010 dan Expr1011 .
- Gabung Nested Loops hanya mengembalikan Users.IDs yang memiliki kecocokan di subtree sebelumnya. Karena pushdown predikat, semua baris yang dikembalikan dari pencarian indeks di IX_NC_REPUTATION dikembalikan.
- Gabung Nested terakhir bergabung: Untuk setiap catatan Tulisan, menghasilkan Pengguna. Di mana kecocokan ditemukan dalam dataset di bawah ini.
SELECT Users.Id FROM dbo.Users WHERE Users.Reputation = 5 AND EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id IN (Posts.OwnerUserId, Posts.LastEditorUserId) ) ;
SELECT Users.Id FROM dbo.Users WHERE Users.Reputation = 5 AND ( EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id = Posts.OwnerUserId) OR EXISTS (SELECT 1 FROM dbo.Posts WHERE Users.Id = Posts.LastEditorUserId) ) ;