Apa yang membuat pernyataan SQL berharga?

253

Menurut definisi (setidaknya dari apa yang saya lihat) sargable berarti bahwa kueri mampu membuat mesin kueri mengoptimalkan rencana eksekusi yang digunakan kueri. Saya sudah mencoba mencari jawabannya, tetapi sepertinya tidak banyak tentang masalah ini. Jadi pertanyaannya adalah, apa yang membuat atau tidak membuat query SQL sargable? Dokumentasi apa pun akan sangat dihargai.

Untuk referensi: SARGable

DForck42
sumber
58
+1 untuk "sargable". Itu kata-kata saya hari ini untuk hari ini. :-p
BFree
1
Saya mungkin juga menambahkan ke jawaban Adam, bahwa banyak informasi yang sangat khusus untuk setiap mesin DB.
Hoagie
31
SARG = Cari ARGument. Lucunya adalah: "SARG" dalam bahasa Jerman berarti "Peti mati", jadi saya harus selalu tersenyum ketika orang berbicara tentang SARGABLE - dapat dimasukkan ke dalam peti mati? :-)
marc_s
sargability tergantung pada lingkungan Anda. MySQL didokumentasikan di sini: dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Frank Farmer
Memiliki bidang teks bebas alih-alih "tabel pencarian" juga bertentangan dengan semangat membuat kueri yang dapat ditagih. Pengguna salah mengeja hal-hal ketika memasukkan teks bebas (misalnya nama kota), sedangkan tabel pencarian memaksa pengguna untuk memilih entri yang dieja dengan benar. Layak sedikit masalah ekstra, karena ini dapat diindeks dengan benar daripada menggunakan LIKE '% ...%' dalam predikat.
Insinyur Terbalik

Jawaban:

256

Hal paling umum yang akan membuat kueri tidak dapat dinyalakan adalah menyertakan bidang di dalam fungsi di mana klausa:

SELECT ... FROM ...
WHERE Year(myDate) = 2008

Pengoptimal SQL tidak dapat menggunakan indeks pada myDate, bahkan jika ada. Ini benar-benar harus mengevaluasi fungsi ini untuk setiap baris tabel. Jauh lebih baik untuk digunakan:

WHERE myDate >= '01-01-2008' AND myDate < '01-01-2009'

Beberapa contoh lain:

Bad: Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'
Fixed: Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))

Bad: Select ... WHERE SUBSTRING(DealerName,4) = 'Ford'
Fixed: Select ... WHERE DealerName Like 'Ford%'

Bad: Select ... WHERE DateDiff(mm,OrderDate,GetDate()) >= 30
Fixed: Select ... WHERE OrderDate < DateAdd(mm,-30,GetDate()) 
BradC
sumber
7
Apakah akan memasukkan fungsi di dalam GROUP BYpenyebab permintaan menjadi tidak dapat ditagih?
Mike Bailey
1
Beberapa mesin basis data (Oracle, PostgreSQL) mendukung indeks pada ekspresi, tidak tahu?
Craig
3
Akan versi yang lebih baik dari WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL))menjadi SELECT... FROM ... WHERE FullName = 'Ed Jones' UNION SELECT...FROM...WHERE FullName IS NULL? Saya pernah diberitahu oleh seorang pria optimasi yang menggunakan ATAU di mana klausa dapat membatalkan permintaan ..?
High Plains Grifter
2
@HighPlainsGrifter Anda harus menggunakan UNION ALL pada kueri itu - serikat memiliki perbedaan implisit, yang membuat kueri jauh lebih mahal daripada yang seharusnya ketika Anda harus dataset bersama-sama eksklusif
Devin Lamothe
1
@BradC Di MSSQL 2016, tidak ada perbedaan rencana eksekusi antara Select ... WHERE isNull(FullName,'Ed Jones') = 'Ed Jones'dan Select ... WHERE ((FullName = 'Ed Jones') OR (FullName IS NULL)). Keduanya menggunakan indeks pada FullName dan melakukan pencarian indeks.
CEGRD
79

Jangan lakukan ini:

WHERE Field LIKE '%blah%'

Itu menyebabkan pemindaian tabel / indeks, karena nilai LIKE dimulai dengan karakter wildcard.

Jangan lakukan ini:

WHERE FUNCTION(Field) = 'BLAH'

Itu menyebabkan pemindaian tabel / indeks.

Server database harus mengevaluasi FUNGSI () terhadap setiap baris dalam tabel dan kemudian membandingkannya dengan 'BLAH'.

Jika memungkinkan, lakukan secara terbalik:

WHERE Field = INVERSE_FUNCTION('BLAH')

Ini akan menjalankan INVERSE_FUNCTION () terhadap parameter sekali dan masih akan memungkinkan penggunaan indeks.

pantai
sumber
5
Saran Anda dengan membalik fungsi akan benar-benar hanya berfungsi ketika fungsi round-trip data (artinya f (f (n)) = n).
Adam Robinson
5
Benar. Saya mempertimbangkan untuk menambahkan INVERSE_FUNCTION tetapi tidak ingin membingungkan. Saya akan mengubahnya.
pantai
9

Dalam jawaban ini saya berasumsi bahwa basis data memiliki cukup indeks cakupan. Ada cukup banyak pertanyaan tentang topik ini .

Banyak kali sargabilitas kueri ditentukan oleh titik kritis indeks terkait. Titik kritis mendefinisikan perbedaan antara mencari dan memindai indeks saat bergabung dengan satu tabel atau hasil yang ditetapkan ke yang lain. Satu pencarian tentu saja jauh lebih cepat daripada memindai seluruh tabel, tetapi ketika Anda harus mencari banyak baris, pemindaian bisa lebih masuk akal.

Jadi antara lain pernyataan SQL lebih mahal ketika optimizer mengharapkan jumlah baris yang dihasilkan dari satu tabel menjadi kurang dari titik kritis indeks yang mungkin pada tabel berikutnya.

Anda dapat menemukan pos dan contoh terperinci di sini .

Dries Van Hansewijck
sumber
4

Untuk suatu operasi yang dianggap sargable, tidaklah cukup baginya untuk hanya dapat menggunakan indeks yang ada. Dalam contoh di atas, menambahkan pemanggilan fungsi terhadap kolom yang diindeks di mana klausa, kemungkinan besar masih akan mengambil keuntungan dari indeks yang ditentukan. Ini akan "memindai" alias mengambil semua nilai dari kolom itu (indeks) dan kemudian menghilangkan yang tidak cocok dengan nilai filter yang disediakan. Masih belum cukup efisien untuk tabel dengan jumlah baris yang tinggi. Yang benar-benar mendefinisikan sargability adalah kemampuan kueri untuk menelusuri indeks b-tree menggunakan metode pencarian biner yang bergantung pada setengah-set eliminasi untuk array item yang diurutkan. Dalam SQL, itu akan ditampilkan pada rencana eksekusi sebagai "indeks pencarian".

pengguna2011845
sumber