Tôi có một vấn đề hiểu tại sao máy chủ SQL quyết định gọi hàm do người dùng xác định cho mọi giá trị trong bảng mặc dù chỉ nên tìm nạp một hàng. SQL thực tế phức tạp hơn nhiều, nhưng tôi đã có thể giảm vấn đề xuống đây:
select
S.GROUPCODE,
H.ORDERCATEGORY
from
ORDERLINE L
join ORDERHDR H on H.ORDERID = L.ORDERID
join PRODUCT P on P.PRODUCT = L.PRODUCT
cross apply dbo.GetGroupCode (P.FACTORY) S
where
L.ORDERNUMBER = 'XXX/YYY-123456' and
L.RMPHASE = '0' and
L.ORDERLINE = '01'
Đối với truy vấn này, SQL Server quyết định gọi hàm GetgroupCode cho mọi giá trị duy nhất tồn tại trong Bảng SẢN PHẨM, mặc dù ước tính và số lượng hàng thực tế được trả về từ ORDERLINE là 1 (đó là khóa chính):
Cùng một kế hoạch trong kế hoạch thám hiểm hiển thị số hàng:
Những cái bàn:
ORDERLINE: 1.5M rows, primary key: ORDERNUMBER + ORDERLINE + RMPHASE (clustered)
ORDERHDR: 900k rows, primary key: ORDERID (clustered)
PRODUCT: 6655 rows, primary key: PRODUCT (clustered)
Chỉ số đang được sử dụng để quét là:
create unique nonclustered index PRODUCT_FACTORY on PRODUCT (PRODUCT, FACTORY)
Hàm thực sự phức tạp hơn một chút, nhưng điều tương tự cũng xảy ra với hàm đa câu giả như thế này:
create function GetGroupCode (@FACTORY varchar(4))
returns @t table(
TYPE varchar(8),
GROUPCODE varchar(30)
)
as begin
insert into @t (TYPE, GROUPCODE) values ('XX', 'YY')
return
end
Tôi đã có thể "sửa" hiệu suất bằng cách buộc máy chủ SQL tìm nạp 1 sản phẩm hàng đầu, mặc dù 1 là tối đa có thể tìm thấy:
select
S.GROUPCODE,
H.ORDERCAT
from
ORDERLINE L
join ORDERHDR H
on H.ORDERID = M.ORDERID
cross apply (select top 1 P.FACTORY from PRODUCT P where P.PRODUCT = L.PRODUCT) P
cross apply dbo.GetGroupCode (P.FACTORY) S
where
L.ORDERNUMBER = 'XXX/YYY-123456' and
L.RMPHASE = '0' and
L.ORDERLINE = '01'
Sau đó, hình dạng kế hoạch cũng thay đổi thành một cái gì đó mà tôi mong đợi ban đầu:
Tôi cũng mặc dù rằng chỉ mục PRODUCT_FACTORY nhỏ hơn chỉ mục được phân cụm, SẢN PHẨM sẽ có ảnh hưởng, nhưng ngay cả khi buộc truy vấn phải sử dụng PRODUCT_PK, kế hoạch vẫn giống như ban đầu, với 6655 lệnh gọi đến hàm.
Nếu tôi hoàn toàn rời khỏi ORDERHDR, thì kế hoạch bắt đầu với vòng lặp lồng nhau giữa ORDERLINE và SẢN PHẨM trước tiên và chức năng chỉ được gọi một lần.
Tôi muốn hiểu lý do của việc này là gì vì tất cả các thao tác được thực hiện bằng khóa chính và cách khắc phục nếu xảy ra trong một truy vấn phức tạp hơn không thể giải quyết dễ dàng.
Chỉnh sửa: Tạo báo cáo bảng:
CREATE TABLE dbo.ORDERHDR(
ORDERID varchar(8) NOT NULL,
ORDERCATEGORY varchar(2) NULL,
CONSTRAINT ORDERHDR_PK PRIMARY KEY CLUSTERED (ORDERID)
)
CREATE TABLE dbo.ORDERLINE(
ORDERNUMBER varchar(16) NOT NULL,
RMPHASE char(1) NOT NULL,
ORDERLINE char(2) NOT NULL,
ORDERID varchar(8) NOT NULL,
PRODUCT varchar(8) NOT NULL,
CONSTRAINT ORDERLINE_PK PRIMARY KEY CLUSTERED (ORDERNUMBER,ORDERLINE,RMPHASE)
)
CREATE TABLE dbo.PRODUCT(
PRODUCT varchar(8) NOT NULL,
FACTORY varchar(4) NULL,
CONSTRAINT PRODUCT_PK PRIMARY KEY CLUSTERED (PRODUCT)
)