it-swarm.asia

Praktik terbaik antara menggunakan LEFT JOIN atau NOT EXISTS

Apakah ada praktik terbaik antara menggunakan LEFT JOIN atau format NOT EXISTS?

Apa manfaat menggunakan yang satu dari yang lain?

Jika tidak ada, yang mana yang lebih disukai?

SELECT *
FROM tableA A
LEFT JOIN tableB B
     ON A.idx = B.idx
WHERE B.idx IS NULL

SELECT *
FROM tableA A
WHERE NOT EXISTS
(SELECT idx FROM tableB B WHERE B.idx = A.idx)

Saya menggunakan kueri dalam Access melawan database SQL Server.

72

Perbedaan terbesar bukan pada join vs not exist, itu (seperti yang tertulis), the SELECT *.

Pada contoh pertama, Anda mendapatkan semua kolom dari keduanya A dan B, sedangkan dalam contoh kedua, Anda dapatkan hanya kolom dari A.

Dalam SQL Server, varian kedua sedikit lebih cepat dalam contoh yang dibuat sangat sederhana:

Buat dua tabel sampel:

CREATE TABLE dbo.A
(
    A_ID INT NOT NULL
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
);

CREATE TABLE dbo.B
(
    B_ID INT NOT NULL
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
);
GO

Masukkan 10.000 baris ke setiap tabel:

INSERT INTO dbo.A DEFAULT VALUES;
GO 10000

INSERT INTO dbo.B DEFAULT VALUES;
GO 10000

Hapus setiap baris ke-5 dari tabel kedua:

DELETE 
FROM dbo.B 
WHERE B_ID % 5 = 1;

SELECT COUNT(*) -- shows 10,000
FROM dbo.A;

SELECT COUNT(*) -- shows  8,000
FROM dbo.B;

Lakukan dua tes SELECT varian pernyataan:

SELECT *
FROM dbo.A
    LEFT JOIN dbo.B ON A.A_ID = B.B_ID
WHERE B.B_ID IS NULL;

SELECT *
FROM dbo.A
WHERE NOT EXISTS (SELECT 1
    FROM dbo.B
    WHERE b.B_ID = a.A_ID);

Rencana eksekusi:

enter image description here

Varian kedua tidak perlu melakukan operasi filter karena dapat menggunakan operator anti-semi join kiri.

60
Max Vernon

Logikanya identik, tetapi NOT EXISTS lebih dekat dengan AntiSemiJoin yang Anda minta, dan umumnya lebih disukai. Ini juga menyoroti lebih baik bahwa Anda tidak dapat mengakses kolom di B, karena hanya digunakan sebagai filter (sebagai lawan tersedia dengan nilai NULL).

Beberapa tahun yang lalu (SQL Server 6.0 ish), LEFT JOIN lebih cepat, tapi itu sudah lama tidak terjadi. Hari-hari ini, NOT EXISTS sedikit lebih cepat.


Dampak terbesar dalam Access adalah metode JOIN harus menyelesaikan gabungan sebelum memfilternya, membangun set yang digabungkan dalam memori. Menggunakan NOT EXISTS ia memeriksa baris tetapi tidak mengalokasikan ruang untuk kolom. Plus, ia berhenti mencari begitu menemukan baris. Kinerja sedikit lebih bervariasi di Access, tetapi aturan umum adalah NOT EXISTS cenderung sedikit lebih cepat. Saya akan cenderung mengatakan itu "praktik terbaik", karena ada lebih banyak faktor yang terlibat.

25
Rob Farley

Pengecualian yang saya perhatikan pada NOT EXISTS menjadi superior (namun sedikit) ke LEFT JOIN ... WHERE IS NULL adalah ketika menggunakan Server Tertaut .

Dari memeriksa rencana eksekusi, tampak bahwa NOT EXISTS operator dieksekusi dalam mode nested loop. Dimana dijalankan pada basis per baris (yang saya kira masuk akal).

Contoh rencana eksekusi yang menunjukkan perilaku ini: enter image description here

7
pimbrouwers

Secara umum, mesin akan membuat rencana eksekusi berdasarkan dasarnya pada:

  1. Jumlah baris dalam A dan B
  2. Apakah ada Indeks pada A dan/atau B.
  3. Jumlah baris hasil yang diharapkan (dan baris perantara)
  4. Bentuk kueri input (mis. Pertanyaan Anda)

Untuk (4):

Rencana "tidak ada" mendorong rencana pencarian berdasarkan pada tabel B. Ini adalah pilihan yang baik ketika tabel A kecil dan tabel B besar (dan indeks ada di B).

Rencana "antijoin" adalah pilihan yang baik ketika tabel A sangat besar atau tabel B sangat kecil atau tidak ada indeks pada B dan mengembalikan set hasil yang besar.

Namun itu hanya "dorongan", seperti input tertimbang. A (1), (2), (3) yang kuat sering membuat pilihan untuk (4) diperdebatkan.

(Mengabaikan efek dari contoh Anda mengembalikan kolom yang berbeda karena *, dialamatkan oleh jawaban @MaxVernon.).

5
crokusek