Saya biasa menulis cek EXISTS saya seperti ini:
IF EXISTS (SELECT * FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Where Columns=@Filters
END
Salah satu DBA dalam kehidupan sebelumnya mengatakan kepada saya bahwa ketika saya melakukan EXISTS
klausul, gunakan SELECT 1
bukanSELECT *
IF EXISTS (SELECT 1 FROM TABLE WHERE Columns=@Filters)
BEGIN
UPDATE TABLE SET ColumnsX=ValuesX WHERE Columns=@Filters
END
Apakah ini benar-benar membuat perbedaan?
sql
sql-server
tsql
Raj More
sumber
sumber
Jawaban:
Tidak, SQL Server pintar dan tahu itu digunakan untuk yang sudah ada, dan mengembalikan NO DATA ke sistem.
Quoth Microsoft: http://technet.microsoft.com/en-us/library/ms189259.aspx?ppud=4
Untuk memeriksa diri Anda sendiri, coba jalankan yang berikut ini:
SELECT whatever FROM yourtable WHERE EXISTS( SELECT 1/0 FROM someothertable WHERE a_valid_clause )
Jika itu benar-benar melakukan sesuatu dengan daftar SELECT, itu akan melempar div dengan kesalahan nol. Tidak.
EDIT: Catatan, Standar SQL sebenarnya berbicara tentang ini.
ANSI SQL 1992 Standard, hal 191 http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
sumber
EXISTS
Caranya dengan 1/0 bahkan dapat diperluas untuk iniSELECT 1 WHERE EXISTS(SELECT 1/0)
... tampaknya langkah yang lebih abstrak kemudian sebagai yang keduaSELECT
tidak memilikiFROM
klausulSELECT COUNT(*) WHERE EXISTS(SELECT 1/0)
. ASELECT
tanpaFROM
di SQL Server diperlakukan seolah-olah mengakses tabel baris tunggal (misalnya mirip dengan memilih daridual
tabel di RDBMS lain)SELECT
membuat tabel 1 baris sebelum melakukan hal lain jadi meskipun1/0
sampah tabel 1 baris masihEXISTS
?Alasan kesalahpahaman ini mungkin karena keyakinan bahwa ia akan membaca semua kolom. Sangat mudah untuk melihat bahwa bukan ini masalahnya.
CREATE TABLE T ( X INT PRIMARY KEY, Y INT, Z CHAR(8000) ) CREATE NONCLUSTERED INDEX NarrowIndex ON T(Y) IF EXISTS (SELECT * FROM T) PRINT 'Y'
Memberikan rencana
Ini menunjukkan bahwa SQL Server dapat menggunakan indeks tersempit yang tersedia untuk memeriksa hasil meskipun pada kenyataannya indeks tidak menyertakan semua kolom. Akses indeks berada di bawah operator semi-join yang berarti dapat menghentikan pemindaian segera setelah baris pertama dikembalikan.
Jadi jelas sekali keyakinan di atas salah.
Namun Conor Cunningham dari tim Pengoptimal Kueri menjelaskan di sini bahwa ia biasanya menggunakan
SELECT 1
dalam kasus ini karena dapat membuat perbedaan kinerja kecil dalam kompilasi kueri.Saya menguji empat kemungkinan cara untuk mengekspresikan kueri ini pada tabel kosong dengan berbagai jumlah kolom.
SELECT 1
vsSELECT *
vsSELECT Primary_Key
vsSELECT Other_Not_Null_Column
.Saya menjalankan kueri dalam satu putaran menggunakan
OPTION (RECOMPILE)
dan mengukur jumlah rata-rata eksekusi per detik. Hasil di bawah+-------------+----------+---------+---------+--------------+ | Num of Cols | * | 1 | PK | Not Null col | +-------------+----------+---------+---------+--------------+ | 2 | 2043.5 | 2043.25 | 2073.5 | 2067.5 | | 4 | 2038.75 | 2041.25 | 2067.5 | 2067.5 | | 8 | 2015.75 | 2017 | 2059.75 | 2059 | | 16 | 2005.75 | 2005.25 | 2025.25 | 2035.75 | | 32 | 1963.25 | 1967.25 | 2001.25 | 1992.75 | | 64 | 1903 | 1904 | 1936.25 | 1939.75 | | 128 | 1778.75 | 1779.75 | 1799 | 1806.75 | | 256 | 1530.75 | 1526.5 | 1542.75 | 1541.25 | | 512 | 1195 | 1189.75 | 1203.75 | 1198.5 | | 1024 | 694.75 | 697 | 699 | 699.25 | +-------------+----------+---------+---------+--------------+ | Total | 17169.25 | 17171 | 17408 | 17408 | +-------------+----------+---------+---------+--------------+
Seperti yang dapat dilihat, tidak ada pemenang yang konsisten antara
SELECT 1
danSELECT *
dan perbedaan antara kedua pendekatan dapat diabaikan. TheSELECT Not Null col
danSELECT PK
tampil sedikit lebih cepat sekalipun.Keempat kueri tersebut menurunkan kinerja saat jumlah kolom dalam tabel meningkat.
Karena tabel kosong, hubungan ini tampaknya hanya dapat dijelaskan dengan jumlah metadata kolom. Karena
COUNT(1)
mudah untuk melihat bahwa ini akan ditulis ulangCOUNT(*)
di beberapa titik dalam proses dari bawah.SET SHOWPLAN_TEXT ON; GO SELECT COUNT(1) FROM master..spt_values
Yang memberikan rencana berikut
|--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1004],0))) |--Stream Aggregate(DEFINE:([Expr1004]=Count(*))) |--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))
Melampirkan debugger ke proses SQL Server dan secara acak melanggar saat menjalankan di bawah ini
DECLARE @V int WHILE (1=1) SELECT @V=1 WHERE EXISTS (SELECT 1 FROM ##T) OPTION(RECOMPILE)
Saya menemukan bahwa dalam kasus di mana tabel memiliki 1.024 kolom sebagian besar waktu tumpukan panggilan terlihat seperti di bawah ini menunjukkan bahwa memang menghabiskan sebagian besar waktu memuat metadata kolom bahkan ketika
SELECT 1
digunakan (Untuk kasus di mana tabel memiliki 1 kolom yang secara acak melanggar tidak mencapai sedikit tumpukan panggilan ini dalam 10 upaya)Upaya pembuatan profil manual ini didukung oleh profiler kode VS 2012 yang menunjukkan pilihan fungsi yang sangat berbeda yang memakan waktu kompilasi untuk dua kasus ( kolom 15 Fungsi Teratas 1024 vs kolom 15 Fungsi Teratas 1 ).
Baik versi
SELECT 1
danSELECT *
akhirnya memeriksa izin kolom dan gagal jika pengguna tidak diberikan akses ke semua kolom dalam tabel.Contoh yang saya kutip dari percakapan di heap
CREATE USER blat WITHOUT LOGIN; GO CREATE TABLE dbo.T ( X INT PRIMARY KEY, Y INT, Z CHAR(8000) ) GO GRANT SELECT ON dbo.T TO blat; DENY SELECT ON dbo.T(Z) TO blat; GO EXECUTE AS USER = 'blat'; GO SELECT 1 WHERE EXISTS (SELECT 1 FROM T); /* ↑↑↑↑ Fails unexpectedly with The SELECT permission was denied on the column 'Z' of the object 'T', database 'tempdb', schema 'dbo'.*/ GO REVERT; DROP USER blat DROP TABLE T
Jadi orang mungkin berspekulasi bahwa perbedaan kecil yang terlihat saat menggunakan
SELECT some_not_null_col
adalah bahwa itu hanya berakhir memeriksa izin pada kolom tertentu (meskipun masih memuat metadata untuk semua). Namun ini tampaknya tidak sesuai dengan fakta karena perbedaan persentase antara kedua pendekatan jika ada yang semakin kecil karena jumlah kolom dalam tabel yang mendasarinya meningkat.Bagaimanapun saya tidak akan terburu-buru dan mengubah semua pertanyaan saya ke formulir ini karena perbedaannya sangat kecil dan hanya terlihat selama kompilasi kueri. Menghapus
OPTION (RECOMPILE)
sehingga eksekusi selanjutnya dapat menggunakan rencana cache memberi berikut ini.+-------------+-----------+------------+-----------+--------------+ | Num of Cols | * | 1 | PK | Not Null col | +-------------+-----------+------------+-----------+--------------+ | 2 | 144933.25 | 145292 | 146029.25 | 143973.5 | | 4 | 146084 | 146633.5 | 146018.75 | 146581.25 | | 8 | 143145.25 | 144393.25 | 145723.5 | 144790.25 | | 16 | 145191.75 | 145174 | 144755.5 | 146666.75 | | 32 | 144624 | 145483.75 | 143531 | 145366.25 | | 64 | 145459.25 | 146175.75 | 147174.25 | 146622.5 | | 128 | 145625.75 | 143823.25 | 144132 | 144739.25 | | 256 | 145380.75 | 147224 | 146203.25 | 147078.75 | | 512 | 146045 | 145609.25 | 145149.25 | 144335.5 | | 1024 | 148280 | 148076 | 145593.25 | 146534.75 | +-------------+-----------+------------+-----------+--------------+ | Total | 1454769 | 1457884.75 | 1454310 | 1456688.75 | +-------------+-----------+------------+-----------+--------------+
Skrip pengujian yang saya gunakan dapat ditemukan di sini
sumber
Cara terbaik untuk mengetahuinya adalah dengan menguji performa kedua versi dan memeriksa rencana eksekusi untuk kedua versi. Pilih tabel dengan banyak kolom.
sumber
Tidak ada perbedaan di SQL Server dan tidak pernah menjadi masalah di SQL Server. Pengoptimal tahu bahwa mereka sama. Jika Anda melihat rencana eksekusi, Anda akan melihat bahwa mereka identik.
sumber
Secara pribadi saya merasa sangat, sangat sulit untuk percaya bahwa mereka tidak mengoptimalkan rencana kueri yang sama. Tetapi satu-satunya cara untuk mengetahui situasi khusus Anda adalah dengan mengujinya. Jika Anda melakukannya, laporkan kembali!
sumber
Tidak ada perbedaan nyata tetapi mungkin ada kinerja yang sangat kecil. Sebagai aturan praktis, Anda tidak boleh meminta lebih banyak data daripada yang Anda butuhkan.
sumber