ฟังก์ชั่นมูลค่าตารางหลายงบส่งกลับผลลัพธ์ในตัวแปรตาราง
ผลลัพธ์เหล่านี้เคยถูกนำมาใช้ซ้ำหรือฟังก์ชั่นจะถูกประเมินอย่างเต็มที่ทุกครั้งที่มีการเรียกใช้หรือไม่
ฟังก์ชั่นมูลค่าตารางหลายงบส่งกลับผลลัพธ์ในตัวแปรตาราง
ผลลัพธ์เหล่านี้เคยถูกนำมาใช้ซ้ำหรือฟังก์ชั่นจะถูกประเมินอย่างเต็มที่ทุกครั้งที่มีการเรียกใช้หรือไม่
คำตอบ:
ผลลัพธ์ของฟังก์ชั่นมูลค่าตารางหลายคำสั่ง (msTVF) จะไม่ถูกแคชหรือนำกลับมาใช้ซ้ำระหว่างคำสั่ง (หรือการเชื่อมต่อ) แต่มีสองวิธีที่ผลลัพธ์ msTVF อาจนำกลับมาใช้ใหม่ในคำสั่งเดียวกัน ในขอบเขตนั้น msTVF ไม่จำเป็นต้องมีการเติมคำซ้ำในแต่ละครั้งที่มีการเรียก
msTVF นี้ (ไม่มีประสิทธิภาพโดยเจตนา) ส่งคืนช่วงจำนวนเต็มตามที่ระบุโดยมีการประทับเวลาในแต่ละแถว:
IF OBJECT_ID(N'dbo.IntegerRange', 'TF') IS NOT NULL
DROP FUNCTION dbo.IntegerRange;
GO
CREATE FUNCTION dbo.IntegerRange (@From integer, @To integer)
RETURNS @T table
(
n integer PRIMARY KEY,
ts datetime DEFAULT CURRENT_TIMESTAMP
)
WITH SCHEMABINDING
AS
BEGIN
WHILE @From <= @To
BEGIN
INSERT @T (n)
VALUES (@From);
SET @From = @From + 1;
END;
RETURN;
END;
หากพารามิเตอร์ทั้งหมดในการเรียกใช้ฟังก์ชันเป็นค่าคงที่ (หรือค่าคงที่รันไทม์) แผนการดำเนินการจะเติมผลลัพธ์ของตัวแปรตารางหนึ่งครั้ง ส่วนที่เหลือของแผนอาจเข้าถึงตัวแปรตารางหลายครั้ง ธรรมชาติของตัวแปรตารางสามารถรับรู้ได้จากแผนการดำเนินการ ตัวอย่างเช่น:
SELECT
IR.n,
IR.ts
FROM dbo.IntegerRange(1, 5) AS IR
ORDER BY
IR.n;
ส่งคืนผลลัพธ์ที่คล้ายกับ:
แผนการดำเนินการคือ:
ตัวดำเนินการลำดับจะเรียกใช้ตัวดำเนินการฟังก์ชันที่ประเมินค่าในตารางก่อนซึ่งจะเติมตัวแปรตาราง (หมายเหตุตัวดำเนินการนี้จะไม่ส่งคืนแถว) ถัดไป Sequence เรียกอินพุตที่สองซึ่งส่งคืนเนื้อหาของตัวแปรตาราง (โดยใช้การสแกนดัชนีแบบคลัสเตอร์ในกรณีนี้)
ของกำนัลที่แผนกำลังใช้ผลลัพธ์ตารางตัวแปร 'คงที่' คือตัวดำเนินการฟังก์ชันที่ประเมินค่าตารางด้านล่างของลำดับ - ตัวแปรตารางจะต้องมีการเติมข้อมูลให้สมบูรณ์ก่อนที่ส่วนที่เหลือของแผนจะไปได้
เพื่อแสดงผลลัพธ์ของตัวแปรตารางที่เข้าถึงได้มากกว่าหนึ่งครั้งเราจะใช้ตารางที่สองที่มีจำนวนแถวตั้งแต่ 1 ถึง 5:
IF OBJECT_ID(N'dbo.T', 'U') IS NOT NULL
DROP TABLE dbo.T;
CREATE TABLE dbo.T (i integer NOT NULL);
INSERT dbo.T (i)
VALUES (1), (2), (3), (4), (5);
และแบบสอบถามใหม่ที่เข้าร่วมในตารางนี้ในฟังก์ชันของเรา (ซึ่งสามารถเขียนเป็นAPPLY
)
SELECT T.i,
IR.n,
IR.ts
FROM dbo.T AS T
JOIN dbo.IntegerRange(1, 5) AS IR
ON IR.n = T.i;
ผลลัพธ์คือ:
แผนการดำเนินการ:
ก่อนหน้านี้ Sequence จะเติมผลลัพธ์ของตัวแปรตาราง msTVF ก่อน ถัดไปจะใช้ลูปซ้อนกันเพื่อเข้าร่วมแต่ละแถวจากตารางT
หนึ่งไปยังอีกแถวหนึ่งจากผลลัพธ์ msTVF เนื่องจากนิยามฟังก์ชันรวมดัชนีที่มีประโยชน์ไว้ในตัวแปรตารางจึงสามารถใช้การค้นหาดัชนีได้
ประเด็นสำคัญคือเมื่อพารามิเตอร์ของ msTVF เป็นค่าคงที่ (รวมถึงตัวแปร & พารามิเตอร์) หรือถือว่าเป็นค่าคงที่แบบรันไทม์สำหรับคำสั่งโดยโปรแกรมการดำเนินการแผนจะมีตัวดำเนินการแยกกันสองตัวสำหรับผลลัพธ์ตัวแปรตาราง msTVF: หนึ่งเพื่อเติม ตาราง; อีกรายการหนึ่งเพื่อเข้าถึงผลลัพธ์อาจเข้าถึงตารางหลายครั้งและอาจใช้ดัชนีที่ประกาศไว้ในนิยามฟังก์ชัน
เพื่อเน้นความแตกต่างเมื่อใช้พารามิเตอร์ที่มีความสัมพันธ์ (การอ้างอิงภายนอก) หรือการใช้ฟังก์ชั่นที่ไม่คงที่เราจะเปลี่ยนเนื้อหาของตารางT
เพื่อให้ฟังก์ชั่นมีงานให้ทำมากมาย:
TRUNCATE TABLE dbo.T;
INSERT dbo.T (i)
VALUES (50001), (50002), (50003), (50004), (50005);
แบบสอบถามที่แก้ไขแล้วต่อไปนี้ใช้การอ้างอิงภายนอกไปยังตารางT
ในหนึ่งในพารามิเตอร์ฟังก์ชัน:
SELECT T.i,
IR.n,
IR.ts
FROM dbo.T AS T
CROSS APPLY dbo.IntegerRange(1, T.i) AS IR
WHERE IR.n = T.i;
ข้อความค้นหานี้ใช้เวลาประมาณ8 วินาทีในการส่งคืนผลลัพธ์เช่น:
ts
ขอให้สังเกตความแตกต่างของเวลาระหว่างแถวในคอลัมน์ WHERE
ข้อ จำกัด ผลสุดท้ายสำหรับการส่งออกอย่างสมเหตุสมผลขนาด แต่ฟังก์ชั่นที่ไม่มีประสิทธิภาพยังคงใช้เวลาในขณะที่จะเติมตัวแปรตารางที่มี 50,000 แปลกแถว (ขึ้นอยู่กับค่าความสัมพันธ์ของi
จากตารางT
)
แผนการดำเนินการคือ:
สังเกตเห็นการขาดตัวดำเนินการลำดับ ขณะนี้มีตัวดำเนินการ Table Valued Function หนึ่งเดียวที่เติมตัวแปรตารางและส่งคืนแถวในแต่ละการวนซ้ำของการรวมลูปซ้อนกัน
เพื่อความชัดเจน: มีเพียง 5 แถวในตาราง T ตัวดำเนินการฟังก์ชันประเมินค่าตารางจะทำงาน 5 ครั้ง มันสร้างแถว 50,001 ในการทำซ้ำครั้งแรก 50,002 ในแถวที่สอง ... และอื่น ๆ ตัวแปรตารางคือ 'ถูกโยนทิ้ง' (ตัด) ระหว่างการวนซ้ำดังนั้นการเรียกห้าครั้งแต่ละครั้งจึงเป็นประชากรเต็มจำนวน นี่คือสาเหตุที่มันช้ามากและแต่ละแถวใช้เวลาประมาณเดียวกันในการปรากฏในผลลัพธ์
หมายเหตุด้านข้าง:
ตามปกติแล้วสถานการณ์ด้านบนมีเจตนาที่จะแสดงให้เห็นว่าประสิทธิภาพที่ไม่ดีสามารถเกิดขึ้นได้อย่างไรเมื่อ msTVF ส่งผลให้เกิดแถวจำนวนมากในการทำซ้ำแต่ละครั้ง
ที่เหมาะสมดำเนินการตามรหัสข้างต้นจะตั้งทั้งพารามิเตอร์ msTVF ไปi
และลบซ้ำซ้อนWHERE
ข้อ ตัวแปรตารางจะยังคงถูกตัดทอนและ repopulated ในแต่ละการทำซ้ำ แต่มีเพียงหนึ่งแถวในแต่ละครั้ง
นอกจากนี้เรายังสามารถดึงค่าต่ำสุดและi
ค่าสูงสุดจากT
และเก็บไว้ในตัวแปรในขั้นตอนก่อนหน้า การเรียกใช้ฟังก์ชันด้วยตัวแปรแทนพารามิเตอร์ที่มีความสัมพันธ์กันจะอนุญาตให้ใช้รูปแบบตัวแปรตาราง 'คงที่' ได้ตามที่ระบุไว้ก่อนหน้านี้
กลับไปยังที่อยู่ของคำถามเดิมอีกครั้งโดยที่ไม่สามารถใช้รูปแบบสแตติกของ Sequence ได้ SQL Server สามารถหลีกเลี่ยงการตัดทอนและปรับเปลี่ยนตัวแปรตาราง msTVF หากไม่มีพารามิเตอร์ที่สัมพันธ์กันเปลี่ยนไปนับตั้งแต่การวนซ้ำก่อนหน้า
เพื่อสาธิตสิ่งนี้เราจะแทนที่เนื้อหาT
ด้วยค่าที่เหมือนกัน ห้าi
ค่า:
TRUNCATE TABLE dbo.T;
INSERT dbo.T (i)
VALUES (50005), (50005), (50005), (50005), (50005);
แบบสอบถามที่มีพารามิเตอร์ที่เกี่ยวข้องอีกครั้ง:
SELECT T.i,
IR.n,
IR.ts
FROM dbo.T AS T
CROSS APPLY dbo.IntegerRange(1, T.i) AS IR
WHERE IR.n = T.i;
เวลานี้ผลลัพธ์ปรากฏในประมาณ1.5 วินาที :
บันทึกการประทับเวลาที่เหมือนกันในแต่ละแถว ผลลัพธ์ที่แคชในตัวแปรตารางจะถูกใช้ซ้ำสำหรับการทำซ้ำในภายหลังโดยที่ค่าที่สัมพันธ์กันi
จะไม่เปลี่ยนแปลง การใช้ผลลัพธ์ซ้ำเร็วกว่าการแทรก 50,005 แถวในแต่ละครั้ง
แผนการดำเนินการมีลักษณะคล้ายกับก่อนหน้านี้มาก:
ความแตกต่างที่สำคัญอยู่ในคุณสมบัติการตอบกลับจริงและการกรอกลับจริงของตัวดำเนินการฟังก์ชันที่คิดมูลค่าตาราง:
เมื่อพารามิเตอร์ที่สัมพันธ์กันไม่เปลี่ยนแปลง SQL Server สามารถเล่นซ้ำ (ย้อนกลับ) ผลลัพธ์ปัจจุบันในตัวแปรตาราง เมื่อการเปลี่ยนแปลงที่เกี่ยวข้อง SQL Server ต้องตัดทอนและ repopulate ตัวแปรตาราง (rebind) หนึ่ง rebind เกิดขึ้นในการทำซ้ำครั้งแรก; การวนซ้ำที่ตามมาสี่ครั้งจะย้อนกลับทั้งหมดเนื่องจากค่าของT.i
ไม่เปลี่ยนแปลง