Mempersiapkan:
create table dbo.T
(
ID int identity primary key,
XMLDoc xml not null
);
insert into dbo.T(XMLDoc)
select (
select N.Number
for xml path(''), type
)
from (
select top(10000) row_number() over(order by (select null)) as Number
from sys.columns as c1, sys.columns as c2
) as N;
Contoh XML untuk setiap baris:
<Number>314</Number>
Pekerjaan untuk kueri adalah menghitung jumlah baris T
dengan nilai yang ditentukan <Number>
.
Ada dua cara yang jelas untuk melakukan ini:
select count(*)
from dbo.T as T
where T.XMLDoc.value('/Number[1]', 'int') = 314;
select count(*)
from dbo.T as T
where T.XMLDoc.exist('/Number[. eq 314]') = 1;
Ternyata itu value()
dan exists()
membutuhkan dua definisi jalur yang berbeda untuk indeks XML selektif untuk bekerja.
create selective xml index SIX_T on dbo.T(XMLDoc) for
(
pathSQL = '/Number' as sql int singleton,
pathXQUERY = '/Number' as xquery 'xs:double' singleton
);
The sql
versi untuk value()
dan xquery
versi untuk exist()
.
Anda mungkin berpikir bahwa indeks seperti itu akan memberi Anda rencana dengan pencarian yang bagus tetapi indeks XML selektif diimplementasikan sebagai tabel sistem dengan kunci utama T
sebagai kunci utama dari kunci berkerumun dari tabel sistem. Jalur yang ditentukan adalah kolom jarang di tabel itu. Jika Anda menginginkan indeks nilai aktual jalur yang ditentukan, Anda perlu membuat indeks selektif sekunder, satu untuk setiap ekspresi jalur.
create xml index SIX_T_pathSQL on dbo.T(XMLDoc)
using xml index SIX_T for (pathSQL);
create xml index SIX_T_pathXQUERY on dbo.T(XMLDoc)
using xml index SIX_T for (pathXQUERY);
Rencana kueri untuk exist()
pencarian di indeks XML sekunder diikuti oleh pencarian kunci dalam tabel sistem untuk indeks XML selektif (tidak tahu mengapa itu diperlukan) dan akhirnya melakukan pencarian T
untuk memastikan benar-benar ada baris di sana. Bagian terakhir diperlukan karena tidak ada batasan kunci asing antara tabel sistem dan T
.
Rencana value()
kueri tidak begitu bagus. Itu melakukan pemindaian indeks berkerumun T
dengan loop bersarang bergabung melawan pencarian di tabel internal untuk mendapatkan nilai dari kolom jarang dan akhirnya menyaring nilai.
Jika indeks selektif harus digunakan atau tidak diputuskan sebelum optimasi tetapi jika indeks selektif sekunder harus digunakan atau tidak adalah keputusan berdasarkan biaya oleh pengoptimal.
Mengapa indeks selektif sekunder tidak digunakan ketika klausa mana menyaring value()
?
Memperbarui:
Pertanyaannya secara semantik berbeda. Jika Anda menambahkan baris dengan nilai
<Number>313</Number>
<Number>314</Number>`
yang exist()
versi akan menghitung 2 baris dan values()
permintaan akan menghitung 1 baris. Tetapi dengan definisi indeks seperti yang ditentukan di sini menggunakan singleton
direktif SQL Server akan mencegah Anda menambahkan baris dengan banyak <Number>
elemen.
Namun itu tidak memungkinkan kita menggunakan values()
fungsi tanpa menentukan [1]
untuk menjamin kompiler bahwa kita hanya akan mendapatkan nilai tunggal. Itulah [1]
alasan kami memiliki Urut N Teratas dalam value()
rencana.
Sepertinya saya mendekati jawaban di sini ...