SUKA menggunakan indeks, CHARINDEX tidak?

22

Pertanyaan ini terkait dengan pertanyaan lama saya . Query di bawah ini membutuhkan 10 hingga 15 detik untuk dieksekusi:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE (Charindex('123456789',CAST([company].dbo.[customer].[Phone no] AS VARCHAR(MAX)))>0) 

Dalam beberapa artikel saya melihat bahwa menggunakan CASTdan CHARINDEXtidak akan mendapat manfaat dari pengindeksan. Ada juga beberapa artikel yang mengatakan menggunakan LIKE '%abc%'tidak akan mendapat manfaat dari pengindeksan sementara LIKE 'abc%'akan:

http://bytes.com/topic/sql-server/answers/81467-using-charindex-vs-like-where /programming/803783/sql-server-index-any-improvement-for -seperti-pertanyaan http://www.sqlservercentral.com/Forums/Topic186262-8-1.aspx#bm186568

Dalam kasus saya, saya dapat menulis ulang kueri sebagai:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE [company].dbo.[customer].[Phone no]  LIKE '%123456789%'

Kueri ini memberikan output yang sama dengan yang sebelumnya. Saya telah membuat indeks untuk kolom yang tidak tercakup Phone no. Ketika saya menjalankan kueri ini, ia berjalan hanya dalam 1 detik . Ini adalah perubahan besar dibandingkan dengan 14 detik sebelumnya.

Bagaimana LIKE '%123456789%'manfaat dari pengindeksan?

Mengapa artikel yang tercantum menyatakan bahwa itu tidak akan meningkatkan kinerja?

Saya mencoba menulis ulang kueri untuk digunakan CHARINDEX, tetapi kinerjanya masih lambat. Mengapa CHARINDEXtidak mendapat manfaat dari pengindeksan seperti yang tampak pada LIKEkueri?

Permintaan menggunakan CHARINDEX:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

Rencana eksekusi:

masukkan deskripsi gambar di sini

Permintaan menggunakan LIKE:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE[Company].dbo.[customer].[Phone no] LIKE '%9000413237%'

Rencana eksekusi:

SEPERTI rencana kueri

Peneliti IT
sumber

Jawaban:

28

Bagaimana SEPERTI '% 123456789%' mendapat manfaat dari pengindeksan?

Hanya sedikit. Prosesor permintaan dapat memindai seluruh indeks yang tidak tercakup untuk mencari kecocokan, bukan seluruh tabel (indeks berkerumun). Indeks nonclustered umumnya lebih kecil dari tabel yang dibangun, jadi pemindaian indeks nonclustered mungkin lebih cepat.

Kelemahannya, adalah bahwa setiap kolom yang dibutuhkan oleh kueri yang tidak termasuk dalam definisi indeks nonclustered harus dicari di tabel dasar, per baris.

Pengoptimal membuat keputusan antara pemindaian tabel (indeks berkerumun) dan pemindaian indeks yang tidak tercakup dengan pencarian, berdasarkan pada perkiraan biaya. Perkiraan biaya sangat tergantung pada berapa banyak baris yang diharapkanLIKE atau dipilih oleh pengoptimal Anda CHARINDEX.

Mengapa artikel yang tercantum menyatakan bahwa itu tidak akan meningkatkan kinerja?

Untuk LIKEkondisi yang tidak dimulai dengan wildcard, SQL Server dapat melakukan pemindaian sebagian indeks daripada memindai semuanya. Misalnya, LIKE 'A%dapat dievaluasi dengan benar dengan hanya menguji catatan indeks >= 'A'dan < 'B'(nilai batas yang tepat tergantung pada pemeriksaan).

Kueri semacam ini dapat menggunakan kemampuan pencarian indeks b-tree: kita bisa langsung menuju catatan pertama >= 'A'menggunakan b-tree, kemudian memindai maju dalam urutan kunci indeks hingga kami mencapai catatan yang gagal dalam < 'B'pengujian. Karena kita hanya perlu menerapkan LIKEtes pada jumlah baris yang lebih kecil, kinerja umumnya lebih baik.

Sebaliknya, LIKE '%Atidak dapat diubah menjadi pemindaian parsial karena kita tidak tahu harus mulai dari mana atau mengakhiri; catatan apa pun dapat diakhiri 'A', jadi kami tidak dapat meningkatkan pemindaian seluruh indeks dan menguji setiap baris secara individual.

Saya mencoba menulis ulang kueri untuk digunakan CHARINDEX, tetapi kinerjanya masih lambat. Mengapa CHARINDEXtidak mendapat manfaat dari pengindeksan seperti yang tampak pada query LIKE?

Pengoptimal kueri memiliki pilihan yang sama antara pemindaian tabel (indeks berkerumun) dan pemindaian indeks yang tidak tercakup (dengan pencarian) dalam kedua kasus.

Pilihan dibuat di antara keduanya berdasarkan estimasi biaya . Kebetulan SQL Server dapat menghasilkan estimasi yang berbeda untuk kedua metode. Untuk LIKEbentuk kueri, estimasi mungkin dapat menggunakan statistik string khusus untuk menghasilkan estimasi yang cukup akurat. The CHARINDEX > 0Bentuk menghasilkan perkiraan berdasarkan menebak.

Perkiraan yang berbeda sudah cukup untuk membuat pengoptimal memilih Pemindaian CHARINDEXIndeks Berkelompok untuk dan Pemindaian Indeks Nonkluster dengan Pencarian untuk LIKE. Jika Anda memaksa CHARINDEXkueri untuk menggunakan indeks nonclustered dengan sebuah petunjuk, Anda akan mendapatkan paket yang sama seperti untuk LIKE, dan kinerja akan hampir sama:

SELECT
    [Customer name],
    [Sl_No],
    [Id]
FROM dbo.customer WITH (INDEX (f))
WHERE 
    CHARINDEX('9000413237', [Phone no]) >0;

Jumlah baris yang diproses pada saat runtime akan sama untuk kedua metode, hanya saja LIKEformulir menghasilkan estimasi yang lebih akurat dalam kasus ini, sehingga pengoptimal kueri memilih paket yang lebih baik.

Jika Anda menemukan diri Anda LIKE %thing%sering membutuhkan pencarian, Anda mungkin ingin mempertimbangkan teknik yang saya tulis di Trigram Wildcard String Search di SQL Server .

Paul White mengatakan GoFundMonica
sumber
16

SQL Server memelihara statistik pada substring dalam kolom string dalam bentuk percobaan yang dapat digunakan oleh LIKEkueri tetapi tidak oleh CHARINDEX.

Lihat bagian Statistik Ringkasan String untuk lebih lanjut tentang ini.

Beberapa peringatan penting adalah bahwa setiap pelarian wildcard harus dilakukan dengan teknik tanda kurung siku alih-alih ESCAPEkata kunci dan untuk string yang lebih panjang dari 80 karakter hanya 40 karakter pertama dan terakhir yang digunakan.

WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

hanya akan menggunakan tebakan standar untuk predikat ketimpangan bahwa 30% dari baris akan dikembalikan.

The LIKEquery (dalam kasus Anda) mungkin memperkirakan lebih sedikit baris akan cocok predikat.

Perhatikan bahwa wildcard terkemuka masih mencegah pencarian indeks. Seluruh indeks masih dipindai tetapi menggunakan yang berbeda yang lebih sempit dari indeks berkerumun. Indeks yang lebih sempit tidak mencakup semua kolom yang digunakan oleh kueri sehingga paket kedua memerlukan pencarian kunci untuk mengambil kolom yang hilang.

Rencana ini sangat tidak mungkin dipilih dengan perkiraan 30%. SQL Server akan menganggap lebih murah untuk memindai seluruh indeks berkerumun dan menghindari banyak pencarian. Lihat artikel ini pada titik kritis untuk contoh tambahan.

Martin Smith
sumber
saya tidak jelas dengan penjelasan anda. Apakah Anda mengatakan bahwa menggunakan suka lebih baik daripada charindex?
Peneliti IT
3
@ITresearcher - Ya, berpotensi, alih-alih hanya menggunakan tebakan selimut tentang berapa banyak baris akan cocok dengan kondisi ( 30%) itu dapat melihat LIKEpola yang disediakan dan statistik ringkasan string dan memperoleh perkiraan yang lebih akurat. Berbekal itu mungkin akan memilih rencana yang berbeda dan lebih tepat.
Martin Smith
3
... atau, dalam "kasus terburuk", rencana yang sama.
Aaron Bertrand