Permintaan berikut membutuhkan waktu sekitar 10 detik untuk diselesaikan di atas meja dengan catatan 12k
select top (5) *
from "Physician"
where "id" = 1 or contains("lastName", '"a*"')
Tetapi jika saya mengubah klausa di mana juga
where "id" = 1
atau
where contains("lastName", '"a*"')
Itu akan kembali secara instan.
Kedua kolom diindeks dan kolom lastName juga teks lengkap diindeks.
CREATE TABLE Physician
(
id int identity NOT NULL,
firstName nvarchar(100) NOT NULL,
lastName nvarchar(100) NOT NULL
);
ALTER TABLE Physician
ADD CONSTRAINT Physician_PK
PRIMARY KEY CLUSTERED (id);
CREATE NONCLUSTERED INDEX Physician_IX2
ON Physician (firstName ASC);
CREATE NONCLUSTERED INDEX Physician_IX3
ON Physician (lastName ASC);
CREATE FULLTEXT INDEX
ON "Physician" ("firstName" LANGUAGE 0x0, "lastName" LANGUAGE 0x0)
KEY INDEX "Physician_PK"
ON "the_catalog"
WITH stoplist = off;
Berikut adalah Rencana Eksekusi
Apa yang bisa menjadi masalah?
sql-server
sql-server-2008-r2
full-text-search
Hooman Valibeigi
sumber
sumber
Jawaban:
Rencana eksekusi Anda
Saat melihat rencana kueri, kita dapat melihat bahwa satu indeks disentuh untuk melayani dua operasi filter.
Sederhananya, karena operator TOP, tujuan baris ditetapkan. Lebih banyak informasi & prasyarat tujuan baris dapat ditemukan di sini
Dari sumber yang sama:
Seluruh tabel akan diselidiki ke dalam filter dengan menggunakan setengah bergabung kiri yang memiliki sasaran baris, berharap untuk mengembalikan 5 baris secepat dan seefisien mungkin.
Ini tidak terjadi, menghasilkan banyak iterasi atas .Fulltextmatch TVF.
Rekreasi
Berdasarkan rencana Anda , saya dapat membuat kembali masalah Anda:
Menjalankan kueri
Hasil menjadi paket permintaan yang sebanding dengan milik Anda:
Dalam contoh di atas, B tidak ada dalam indeks teks lengkap. Sebagai hasilnya tergantung pada parameter & data seberapa efisiennya rencana kueri.
Penjelasan yang lebih baik tentang ini dapat ditemukan di Row Goals, Bagian 2: Semi Joins oleh Paul White
Misalnya, mengubah predikat sehingga hasilnya lebih cepat ditemukan (di awal pemindaian).
yang
where "id" = 124
akan dihilangkan karena indeks predikat fulltext sudah kembali 5 baris, memuaskanTOP()
predikat.Hasilnya menunjukkan ini juga
Dan eksekusi TVF:
Memasukkan beberapa baris baru
Menjalankan kueri untuk menemukan baris yang dimasukkan sebelumnya ini
Sekali lagi ini menghasilkan terlalu banyak iterasi pada hampir semua baris untuk mengembalikan nilai terakhir tetapi satu yang ditemukan.
Menyelesaikan
Saat menghapus sasaran baris dengan menggunakan traceflag 4138
Pengoptimal menggunakan pola bergabung lebih dekat ke menerapkan
UNION
, dalam kasus kami ini menguntungkan karena mendorong predikat ke masing-masing indeks pencarian berkerumun, dan tidak menggunakan baris yang menyatu dengan operator setengah bergabung kiri.Cara lain untuk menulis ini, tanpa menggunakan traceflag yang disebutkan di atas:
Dengan rencana kueri yang dihasilkan:
di mana fungsi teks lengkap diterapkan secara langsung
Sebagai sidenote, untuk op, kueri hotfix optimizer traceflag 4199 menyelesaikan masalahnya. Dia menerapkan ini dengan menambahkan
OPTION(QUERYTRACEON(4199))
kueri. Saya tidak dapat mereproduksi perilaku itu di pihak saya. Perbaikan terbaru ini mengandung pengoptimalan setengah bergabung:Sumber
Tambahan
Selama pengoptimalan berbasis biaya, pengoptimal juga dapat menambahkan spool indeks ke rencana eksekusi, dilaksanakan oleh
LogOp_Spool Index on fly Eager
(atau mitra fisik)Ini dilakukan dengan dataset saya untuk
TOP(3)
tetapi tidak untukTOP(2)
Sumber
Dengan predikat pencarian yang diterapkan pada spool eager indeks ini:
sumber