ฉันมีปัญหาในการทำความเข้าใจว่าทำไมเซิร์ฟเวอร์ SQL ตัดสินใจที่จะเรียกใช้ฟังก์ชันที่ผู้ใช้กำหนดสำหรับทุกค่าในตารางแม้ว่าควรดึงข้อมูลได้เพียงหนึ่งแถว SQL จริงมีความซับซ้อนมากขึ้น แต่ฉันสามารถลดปัญหาลงได้ดังนี้
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'
สำหรับการสืบค้นนี้ SQL Server ตัดสินใจที่จะเรียกใช้ฟังก์ชัน GetGroupCode สำหรับทุกค่าเดียวที่มีอยู่ในตารางผลิตภัณฑ์แม้ว่าค่าประมาณการและจำนวนแถวที่แท้จริงที่ส่งคืนจาก ORDERLINE คือ 1 (เป็นคีย์หลัก):
แผนเดียวกันใน explorer แผนแสดงจำนวนแถว:
โต๊ะ:
ORDERLINE: 1.5M rows, primary key: ORDERNUMBER + ORDERLINE + RMPHASE (clustered)
ORDERHDR: 900k rows, primary key: ORDERID (clustered)
PRODUCT: 6655 rows, primary key: PRODUCT (clustered)
ดัชนีที่ใช้สำหรับการสแกนคือ:
create unique nonclustered index PRODUCT_FACTORY on PRODUCT (PRODUCT, FACTORY)
ฟังก์ชั่นนั้นซับซ้อนกว่าเล็กน้อย แต่สิ่งเดียวกันเกิดขึ้นกับฟังก์ชั่นหลายตัวจำลองแบบนี้
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
ฉันสามารถ "แก้ไข" ประสิทธิภาพโดยการบังคับให้เซิร์ฟเวอร์ SQL ดึงผลิตภัณฑ์อันดับ 1 สูงสุดถึงแม้ว่า 1 จะเป็นค่าสูงสุดที่เคยพบ:
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'
จากนั้นรูปร่างของแผนก็เปลี่ยนเป็นสิ่งที่ฉันคาดว่าจะเป็นในตอนแรก:
ฉันยังว่าดัชนี PRODUCT_FACTORY ที่เล็กกว่าดัชนีคลัสเตอร์ PRODUCT_PK จะมีผลกระทบ แต่ถึงแม้จะบังคับให้เคียวรีใช้ PRODUCT_PK แผนก็ยังคงเหมือนเดิมโดยมี 6655 การเรียกใช้ฟังก์ชัน
ถ้าฉันปล่อย ORDERHDR ออกโดยสมบูรณ์แผนจะเริ่มด้วยลูปซ้อนระหว่าง ORDERLINE และ PRODUCT ก่อนและฟังก์ชันจะเรียกใช้เพียงครั้งเดียว
ฉันต้องการที่จะเข้าใจว่าอะไรเป็นสาเหตุของเรื่องนี้ได้เนื่องจากการดำเนินการทั้งหมดดำเนินการโดยใช้คีย์หลักและวิธีแก้ไขหากเกิดขึ้นในคิวรีที่ซับซ้อนมากขึ้นซึ่งไม่สามารถแก้ไขได้อย่างง่ายดาย
แก้ไข: สร้างคำสั่งตาราง:
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)
)