Thiết lập:
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;
XML mẫu cho mỗi hàng:
<Number>314</Number>
Công việc cho truy vấn là đếm số lượng hàng trong T
với giá trị được chỉ định là <Number>
.
Có hai cách rõ ràng để làm điều này:
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;
Nó chỉ ra rằng value()
vàexists()
yêu cầu hai định nghĩa đường dẫn khác nhau để chỉ mục XML chọn lọc hoạt động.
create selective xml index SIX_T on dbo.T(XMLDoc) for
(
pathSQL = '/Number' as sql int singleton,
pathXQUERY = '/Number' as xquery 'xs:double' singleton
);
Các sql
phiên bản là chovalue()
và xquery
phiên bản là cho exist()
.
Bạn có thể nghĩ rằng một chỉ mục như thế sẽ cung cấp cho bạn một kế hoạch với một tìm kiếm tốt nhưng các chỉ mục XML có chọn lọc được triển khai như một bảng hệ thống với khóa chính là T
là khóa chính của khóa cụm của bảng hệ thống. Các đường dẫn được chỉ định là các cột thưa thớt trong bảng đó. Nếu bạn muốn một chỉ mục của các giá trị thực tế của các đường dẫn được xác định, bạn cần tạo một chỉ mục chọn lọc thứ cấp, một chỉ mục cho mỗi biểu thức đường dẫn.
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);
Kế hoạch truy vấn để exist()
tìm kiếm trong chỉ mục XML thứ cấp theo sau là tra cứu khóa trong bảng hệ thống cho chỉ mục XML chọn lọc (không biết tại sao lại cần thiết) và cuối cùng nó sẽ tra cứu T
để đảm bảo thực sự có hàng trong đó. Phần cuối cùng là cần thiết vì không có ràng buộc khóa ngoài giữa bảng hệ thống và T
.
Kế hoạch cho value()
truy vấn không phải là tốt đẹp. Nó thực hiện quét chỉ mục cụmT
với một vòng lặp lồng nhau tham gia tìm kiếm trên bảng bên trong để lấy giá trị từ cột thưa thớt và cuối cùng là lọc các giá trị.
Nếu một chỉ số chọn lọc nên được sử dụng hay không được quyết định trước khi tối ưu hóa nhưng nếu chỉ số chọn lọc thứ cấp có nên được sử dụng hay không thì đó là quyết định dựa trên chi phí của trình tối ưu hóa.
Tại sao chỉ mục chọn lọc thứ cấp không được sử dụng khi mệnh đề where lọc trênvalue()
?
Cập nhật:
Các truy vấn là khác nhau về ngữ nghĩa. Nếu bạn thêm một hàng với giá trị
<Number>313</Number>
<Number>314</Number>`
các exist()
phiên bản sẽ đếm 2 hàng và các values()
truy vấn sẽ đếm 1 hàng. Nhưng với các định nghĩa chỉ mục như chúng được chỉ định ở đây bằng cách sử dụng singleton
SQL Server chỉ thị sẽ ngăn bạn thêm một hàng có nhiều hàng<Number>
phần tử.
Tuy nhiên, điều đó không cho phép chúng tôi sử dụng values()
hàm mà không chỉ định [1]
để đảm bảo trình biên dịch rằng chúng tôi sẽ chỉ nhận được một giá trị duy nhất. Đó [1]
là lý do chúng tôi có Top N Sắp xếp trongvalue()
kế hoạch.
Có vẻ như tôi đang kết thúc câu trả lời ở đây ...