การเปรียบเทียบคำตอบบางส่วนกับคำถาม Palindrome (เฉพาะผู้ใช้ 10k + เท่านั้นเนื่องจากฉันได้ลบคำตอบแล้ว) ฉันจึงได้ผลลัพธ์ที่สับสน
ฉันเสนอTVFซึ่งมีหลายสคีมาซึ่งฉันคิดว่าน่าจะเร็วกว่าการใช้งานฟังก์ชั่นมาตรฐานซึ่งเป็น ฉันยังอยู่ภายใต้ความประทับใจที่ TVF หลายงบจะ "อินไลน์" แม้ว่าฉันจะผิดในการนับที่คุณจะเห็นด้านล่าง คำถามนี้เกี่ยวกับความแตกต่างด้านประสิทธิภาพของ TVF ทั้งสองรูปแบบ ก่อนอื่นคุณจะต้องเห็นรหัส
นี่คือ TVF หลายงบ:
IF OBJECT_ID('dbo.IsPalindrome') IS NOT NULL
DROP FUNCTION dbo.IsPalindrome;
GO
CREATE FUNCTION dbo.IsPalindrome
(
@Word NVARCHAR(500)
)
RETURNS @t TABLE
(
IsPalindrome BIT NOT NULL
)
WITH SCHEMABINDING
AS
BEGIN
DECLARE @IsPalindrome BIT;
DECLARE @LeftChunk NVARCHAR(250);
DECLARE @RightChunk NVARCHAR(250);
DECLARE @StrLen INT;
DECLARE @Pos INT;
SET @RightChunk = '';
SET @IsPalindrome = 0;
SET @StrLen = LEN(@Word) / 2;
IF @StrLen % 2 = 1 SET @StrLen = @StrLen - 1;
SET @Pos = LEN(@Word);
SET @LeftChunk = LEFT(@Word, @StrLen);
WHILE @Pos > (LEN(@Word) - @StrLen)
BEGIN
SET @RightChunk = @RightChunk + SUBSTRING(@Word, @Pos, 1)
SET @Pos = @Pos - 1;
END
IF @LeftChunk = @RightChunk SET @IsPalindrome = 1;
INSERT INTO @t VALUES (@IsPalindrome);
RETURN
END
GO
Inline-TVF:
IF OBJECT_ID('dbo.InlineIsPalindrome') IS NOT NULL
DROP FUNCTION dbo.InlineIsPalindrome;
GO
CREATE FUNCTION dbo.InlineIsPalindrome
(
@Word NVARCHAR(500)
)
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN (
WITH Nums AS
(
SELECT
N = number
FROM
dbo.Numbers
)
SELECT
IsPalindrome =
CASE
WHEN EXISTS
(
SELECT N
FROM Nums
WHERE N <= L / 2
AND SUBSTRING(S, N, 1) <> SUBSTRING(S, 1 + L - N, 1)
)
THEN 0
ELSE 1
END
FROM
(SELECT LTRIM(RTRIM(@Word)), LEN(@Word)) AS v (S, L)
);
GO
Numbers
ตารางในฟังก์ชั่นดังกล่าวข้างต้นหมายถึง:
CREATE TABLE dbo.Numbers
(
Number INT NOT NULL
);
หมายเหตุ: ตารางตัวเลขไม่มีดัชนีและไม่มีคีย์หลักและมี 1,000,000 แถว
ตารางชั่วคราวสำหรับทดสอบเตียง:
IF OBJECT_ID('tempdb.dbo.#Words') IS NOT NULL
DROP TABLE #Words;
GO
CREATE TABLE #Words
(
Word VARCHAR(500) NOT NULL
);
INSERT INTO #Words(Word)
SELECT o.name + REVERSE(w.name)
FROM sys.objects o
CROSS APPLY (
SELECT o.name
FROM sys.objects o
) w;
ในระบบทดสอบของฉันINSERT
ผลลัพธ์ด้านบนมีการแทรกแถวลงใน#Words
ตาราง16,900
ในการทดสอบทั้งสองรูปแบบฉันSET STATISTICS IO, TIME ON;
และใช้สิ่งต่อไปนี้:
SELECT w.Word
, p.IsPalindrome
FROM #Words w
CROSS APPLY dbo.IsPalindrome(w.Word) p
ORDER BY w.Word;
SELECT w.Word
, p.IsPalindrome
FROM #Words w
CROSS APPLY dbo.InlineIsPalindrome(w.Word) p
ORDER BY w.Word;
ฉันคาดว่าInlineIsPalindrome
รุ่นนี้จะเร็วกว่าอย่างมาก แต่ผลลัพธ์ต่อไปนี้ไม่สนับสนุนการคาดคะเนนั้น
หลายงบ TVF:
ตาราง '# A1CE04C3' จำนวนการสแกน 16896, ตรรกะอ่าน 16900, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob การอ่านตรรกะ 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0
ตาราง 'โต๊ะทำงาน' จำนวนการสแกน 0, อ่านโลจิคัล 0, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, ลอจิคัลอ่าน 0, ลูกเทนนิสอ่าน 0,
ล็อคอ่านล่วงหน้าอ่าน 0 ตาราง '#Words' จำนวนการสแกน 1, การอ่านตรรกะ 88, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob ตรรกะอ่าน 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0เวลาดำเนินการของ sql server:
เวลา CPU = 1700 ms, เวลาที่ผ่านไป = 2022 ms
การแยกวิเคราะห์และเวลาในการรวบรวมของ SQL Server: เวลา
CPU = 0 ms, เวลาที่ผ่านไป = 0 ms
Inline TVF:
ตาราง 'ตัวเลข' จำนวนการสแกน 1, ตรรกะอ่าน 1272030, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, การอ่านตรรกะล่วงหน้า lob 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0
ตาราง 'โต๊ะทำงาน' จำนวนการสแกน 0, อ่านโลจิคัล 0, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, ลอจิคัลอ่าน 0, ลูกเทนนิสอ่าน 0,
ล็อคอ่านล่วงหน้าอ่าน 0 ตาราง '#Words' จำนวนการสแกน 1, การอ่านตรรกะ 88, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob ตรรกะอ่าน 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0เวลาดำเนินการของ SQL Server:
เวลา CPU = 137874 ms, เวลาที่ผ่านไป = 139415 ms
การแยกวิเคราะห์และเวลาในการรวบรวมของ SQL Server: เวลา
CPU = 0 ms, เวลาที่ผ่านไป = 0 ms
แผนการดำเนินการมีลักษณะดังนี้:
เหตุใดตัวแปรแบบอินไลน์จึงช้ากว่าชุดคำสั่งหลายคำสั่งมากในกรณีนี้
ในการตอบกลับความคิดเห็นโดย @AaronBertrand ฉันได้แก้ไขdbo.InlineIsPalindrome
ฟังก์ชันเพื่อ จำกัด แถวที่ส่งคืนโดย CTE เพื่อให้ตรงกับความยาวของคำที่ป้อน:
CREATE FUNCTION dbo.InlineIsPalindrome
(
@Word NVARCHAR(500)
)
RETURNS TABLE
WITH SCHEMABINDING
AS RETURN (
WITH Nums AS
(
SELECT
N = number
FROM
dbo.Numbers
WHERE
number <= LEN(@Word)
)
SELECT
IsPalindrome =
CASE
WHEN EXISTS
(
SELECT N
FROM Nums
WHERE N <= L / 2
AND SUBSTRING(S, N, 1) <> SUBSTRING(S, 1 + L - N, 1)
)
THEN 0
ELSE 1
END
FROM
(SELECT LTRIM(RTRIM(@Word)), LEN(@Word)) AS v (S, L)
);
ตามที่ @MartinSmith แนะนำฉันได้เพิ่มคีย์หลักและดัชนีคลัสเตอร์ลงในdbo.Numbers
ตารางซึ่งช่วยได้อย่างแน่นอนและจะใกล้เคียงกับสิ่งที่คาดว่าจะเห็นในสภาพแวดล้อมการผลิต
การเรียกใช้การทดสอบข้างต้นใหม่จะส่งผลให้เกิดสถิติต่อไปนี้:
CROSS APPLY dbo.IsPalindrome(w.Word) p
:
(17424 แถวที่ได้รับผลกระทบ)
ตาราง '# B1104853' จำนวนการสแกน 17420, การอ่านตรรกะ 17424, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, การอ่านตรรกะล่วงหน้า lob 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0
ตาราง 'โต๊ะทำงาน' จำนวนการสแกน 0, อ่านโลจิคัล 0, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, ลอจิคัลอ่าน 0, ลูกเทนนิสอ่าน 0,
ล็อคอ่านล่วงหน้าอ่าน 0 ตาราง '#Words' จำนวนการสแกน 1, อ่านโลจิคัล 90, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, lob อ่านโลจิคัล 0, อ่านทางกายภาพ lob 0, lob อ่านล่วงหน้าอ่าน 0เวลาดำเนินการของ SQL Server:
เวลา CPU = 1763 ms, เวลาที่ผ่านไป = 2192 ms
dbo.FunctionIsPalindrome(w.Word)
:
(17424 แถวที่ได้รับผลกระทบ)
ตาราง 'Worktable' จำนวนการสแกน 0, อ่านโลจิคัล 0, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, ลอจิคัลอ่าน 0, ลูกเทนนิสอ่าน 0,
ล็อคอ่านล่วงหน้าอ่าน 0 ตาราง '#Words' จำนวนการสแกน 1, อ่านโลจิคัล 90, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, lob อ่านโลจิคัล 0, อ่านทางกายภาพ lob 0, lob อ่านล่วงหน้าอ่าน 0เวลาดำเนินการของ SQL Server:
เวลา CPU = 328 ms, เวลาที่ผ่านไป = 424 ms
CROSS APPLY dbo.InlineIsPalindrome(w.Word) p
:
(17424 แถวที่ได้รับผลกระทบ)
ตาราง 'หมายเลข' จำนวนการสแกน 1, ตรรกะอ่าน 237100, การอ่านทางกายภาพ 0, การอ่านล่วงหน้าอ่าน 0, lob ตรรกะอ่าน 0, lob การอ่านทางกายภาพ 0, lob การอ่านล่วงหน้าอ่าน 0
ตาราง 'โต๊ะทำงาน' จำนวนการสแกน 0, อ่านโลจิคัล 0, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, ลอจิคัลอ่าน 0, ลูกเทนนิสอ่าน 0,
ล็อคอ่านล่วงหน้าอ่าน 0 ตาราง '#Words' จำนวนการสแกน 1, อ่านโลจิคัล 90, อ่านฟิสิคัล 0, อ่านล่วงหน้าอ่าน 0, lob อ่านโลจิคัล 0, อ่านทางกายภาพ lob 0, lob อ่านล่วงหน้าอ่าน 0เวลาดำเนินการของ SQL Server:
เวลา CPU = 17737 ms, เวลาที่ผ่านไป = 17946 ms
ฉันกำลังทดสอบสิ่งนี้ใน SQL Server 2012 SP3, v11.0.6020, Developer Edition
นี่คือคำจำกัดความของตารางตัวเลขของฉันโดยมีคีย์หลักและดัชนีคลัสเตอร์:
CREATE TABLE dbo.Numbers
(
Number INT NOT NULL
CONSTRAINT PK_Numbers
PRIMARY KEY CLUSTERED
);
;WITH n AS
(
SELECT v.n
FROM (
VALUES (1)
,(2)
,(3)
,(4)
,(5)
,(6)
,(7)
,(8)
,(9)
,(10)
) v(n)
)
INSERT INTO dbo.Numbers(Number)
SELECT ROW_NUMBER() OVER (ORDER BY n1.n)
FROM n n1
, n n2
, n n3
, n n4
, n n5
, n n6;