Trình tối ưu hóa truy vấn không có toán tử n-ary, mặc dù công cụ thực thi có khá ít. Để minh họa, tôi sẽ sử dụng một phiên bản đơn giản của các bảng của bạn - (SQL Fiddle) .
SELECT DISTINCT
number
INTO foo
FROM master..spt_values
WHERE
number < 1000;
SELECT DISTINCT
number
INTO boo
FROM master..spt_values
WHERE
number between 300 and 1005;
SELECT DISTINCT
number
INTO koo
FROM master..spt_values
WHERE
number > 1006;
ALTER TABLE dbo.foo ADD PRIMARY KEY (number);
ALTER TABLE dbo.boo ADD PRIMARY KEY (number);
ALTER TABLE dbo.koo ADD PRIMARY KEY (number);
Đưa ra các bảng và dữ liệu đó, chúng ta hãy nhìn vào cây đầu vào cho UNION
truy vấn ba chiều :
SELECT f.number FROM dbo.foo AS f
UNION
SELECT b.number FROM dbo.boo AS b
UNION
SELECT k.number FROM dbo.koo AS k
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);
LogOp_Union
OUTPUT(COL: Union1006 )
CHILD(QCOL: [f].number)
CHILD(QCOL: [b].number)
CHILD(QCOL: [k].number)
LogOp_Project
LogOp_Get TBL: dbo.foo(alias TBL: f)
AncOp_PrjList
LogOp_Project
LogOp_Get TBL: dbo.boo(alias TBL: b)
AncOp_PrjList
LogOp_Project
LogOp_Get TBL: dbo.koo(alias TBL: k)
AncOp_PrjList
Toán tử hợp nhất logic có một đầu ra và ba đầu vào con. Sau khi tối ưu hóa dựa trên chi phí, cây vật lý được chọn là hợp nhất với ba đầu vào:
SELECT f.number FROM dbo.foo AS f
UNION
SELECT b.number FROM dbo.boo AS b
UNION
SELECT k.number FROM dbo.koo AS k
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8607);
PhyOp_MergeUnion
PhyOp_Range TBL: dbo.foo(alias TBL: f)(1) ASC
PhyOp_Range TBL: dbo.boo(alias TBL: b)(1) ASC
PhyOp_Range TBL: dbo.koo(alias TBL: k)(1) ASC
Đầu ra của trình tối ưu hóa được làm lại thành một hình thức mà công cụ thực thi (không có liên kết hợp nhất n-ary) có thể xử lý:
Việc viết lại sau tối ưu hóa mở ra n-ary PhyOp_MergeUnion
thành nhiều toán tử Merge Union. Lưu ý rằng tất cả các chi phí ước tính vẫn được liên kết với nhà điều hành công đoàn 'ban đầu' - những người khác có ước tính chi phí bằng không.
Rằng lý do tối ưu hóa về các công đoàn sử dụng toán tử n-ary cung cấp một lời giải thích cho lý do tại sao nó không xem xét việc viết lại ví dụ đầu tiên của bạn vào cùng một kế hoạch như ví dụ thứ hai (liên kết ba chiều là một nút cây).
Lý do thứ hai là không có ràng buộc nào để thực thi "thiếu chồng chéo". Trước khi có các ràng buộc, một liên kết giữa boo
và koo
không thể được đảm bảo không tạo ra các bản sao, vì vậy chúng tôi có một kế hoạch loại bỏ trùng lặp (Liên minh hợp nhất trong trường hợp này):
SELECT b.number FROM dbo.boo AS b
UNION
SELECT k.number FROM dbo.koo AS k;
Việc thêm các ràng buộc sau đây đảm bảo điều kiện không chồng lấp có thể bị vi phạm mà không làm mất hiệu lực các gói được lưu trong bộ nhớ cache cho truy vấn:
ALTER TABLE dbo.foo WITH CHECK ADD CHECK (number < 1000);
ALTER TABLE dbo.boo WITH CHECK ADD CHECK (number BETWEEN 300 AND 1005);
ALTER TABLE dbo.koo WITH CHECK ADD CHECK (number > 1006);
Bây giờ nó an toàn cho trình tối ưu hóa chỉ đơn giản là nối:
Tuy nhiên, ngay cả khi có các ràng buộc đó, truy vấn hợp ba chiều vẫn xuất hiện dưới dạng ba liên kết vì trình tối ưu hóa thường không xem xét việc tách các toán tử n-ary để khám phá các lựa chọn thay thế. Điều hành n-ary rất hữu ích trong việc kiểm soát không gian tìm kiếm; phá vỡ nó thường sẽ phản tác dụng với mục tiêu tối ưu hóa là tìm kiếm một kế hoạch tốt một cách nhanh chóng.
SELECT f.number FROM dbo.foo AS f
UNION
SELECT b.number FROM dbo.boo AS b
UNION
SELECT k.number FROM dbo.koo AS k;
Khi được viết dưới dạng a UNION
và UNION ALL
, một toán tử n-ary không còn có thể được sử dụng (các loại không khớp) để cây có các nút riêng biệt:
SELECT f.number FROM dbo.foo AS f
UNION
SELECT b.number FROM dbo.boo AS b
UNION ALL
SELECT k.number FROM dbo.koo AS k
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8605);
LogOp_UnionAll
OUTPUT(COL: Union1007 )
CHILD(COL: Union1004 )
CHILD(QCOL: [k].number)
LogOp_Union
OUTPUT(COL: Union1004 )
CHILD(QCOL: [f].number)
CHILD(QCOL: [b].number)
LogOp_Project
LogOp_Get TBL: dbo.foo(alias TBL: f)
AncOp_PrjList
LogOp_Project
LogOp_Get TBL: dbo.boo(alias TBL: b)
AncOp_PrjList
LogOp_Project
LogOp_Get TBL: dbo.koo(alias TBL: k)
AncOp_PrjList
MERGE
tham gia được tối ưu hóa hơnSORT
. Nó có độ phức tạp tuyến tính và không yêu cầu cấp bộ nhớ.