Saya punya pertanyaan seperti berikut:
DELETE FROM tblFEStatsBrowsers WHERE BrowserID NOT IN (
SELECT DISTINCT BrowserID FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID IS NOT NULL
)
tblFEStatsBrowsers telah mendapatkan 553 baris.
tblFEStatsPaperHits telah mendapat baris 47.974.301.
tblFEStatsBrowsers:
CREATE TABLE [dbo].[tblFEStatsBrowsers](
[BrowserID] [smallint] IDENTITY(1,1) NOT NULL,
[Browser] [varchar](50) NOT NULL,
[Name] [varchar](40) NOT NULL,
[Version] [varchar](10) NOT NULL,
CONSTRAINT [PK_tblFEStatsBrowsers] PRIMARY KEY CLUSTERED ([BrowserID] ASC)
)
tblFESatsPaperHits:
CREATE TABLE [dbo].[tblFEStatsPaperHits](
[PaperID] [int] NOT NULL,
[Created] [smalldatetime] NOT NULL,
[IP] [binary](4) NULL,
[PlatformID] [tinyint] NULL,
[BrowserID] [smallint] NULL,
[ReferrerID] [int] NULL,
[UserLanguage] [char](2) NULL
)
Ada indeks berkerumun di tblFEStatsPaperHits yang tidak termasuk BrowserID. Karena itu, melakukan query dalam akan membutuhkan pemindaian tabel penuh dari tblFEStatsPaperHits - yang sepenuhnya OK.
Saat ini, pemindaian penuh dieksekusi untuk setiap baris di tblFEStatsBrowsers, yang berarti saya telah mendapatkan 553 pemindaian tabel penuh dari tblFEStatsPaperHits.
Menulis ulang menjadi WHERE EXISTS tidak mengubah rencana:
DELETE FROM tblFEStatsBrowsers WHERE NOT EXISTS (
SELECT * FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID = tblFEStatsBrowsers.BrowserID
)
Namun, seperti yang disarankan oleh Adam Machanic, menambahkan opsi HASH JOIN menghasilkan rencana eksekusi yang optimal (hanya satu pemindaian tblFEStatsPaperHits):
DELETE FROM tblFEStatsBrowsers WHERE NOT EXISTS (
SELECT * FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID = tblFEStatsBrowsers.BrowserID
) OPTION (HASH JOIN)
Sekarang ini bukan pertanyaan bagaimana memperbaikinya - saya bisa menggunakan OPTION (HASH JOIN) atau membuat tabel temp secara manual. Saya lebih bertanya-tanya mengapa pengoptimal kueri akan menggunakan paket yang saat ini dilakukannya.
Karena QO tidak memiliki statistik pada kolom BrowserID, saya menduga itu mengasumsikan yang terburuk - 50 juta nilai yang berbeda, sehingga membutuhkan meja kerja dengan memori / tempdb yang cukup besar. Dengan demikian, cara teraman adalah melakukan pemindaian untuk setiap baris di tblFEStatsBrowsers. Tidak ada hubungan kunci asing antara kolom BrowserID di dua tabel, sehingga QO tidak dapat mengurangi informasi dari tblFEStatsBrowsers.
Apakah ini, sesederhana kedengarannya, alasannya?
Perbarui 1
Untuk memberikan beberapa statistik: OPSI (BERGABUNG
DENGAN HASH ): 208,711 bacaan logis (12 scan)
OPSI (BERGABUNG
DENGAN LOOP, HASH GROUP): 11.008.698 bacaan logis (~ pindai per BrowserID (339))
Tidak ada opsi:
11.008.775 pembacaan logis (~ scan per BrowserID (339))
Perbarui 2
Jawaban luar biasa, kalian semua - terima kasih! Sulit untuk memilih satu saja. Meskipun Martin adalah yang pertama dan Remus memberikan solusi yang sangat baik, saya harus memberikannya kepada Kiwi untuk mengetahui detailnya :)