पैलिंड्रोम प्रश्न पर कुछ उत्तरों की तुलना (10k + उपयोगकर्ता केवल इसलिए, क्योंकि मैंने उत्तर हटा दिया है), मुझे भ्रमित करने वाले परिणाम मिल रहे हैं।
मैंने एक मल्टी-स्टेटमेंट, स्कीमा-बाउंड टीवीएफ प्रस्तावित किया था जो मुझे लगा था कि यह एक मानक फ़ंक्शन चलाने से तेज होगा, जो कि यह है। मैं इस धारणा के तहत था कि मल्टी-स्टेटमेंट टीवीएफ "इनबिल्ड" होगा, हालांकि मैं उस गिनती पर गलत हूं, जैसा कि आप नीचे देखेंगे। यह सवाल टीवीएफ की उन दो शैलियों के प्रदर्शन अंतर के बारे में है। सबसे पहले, आपको कोड देखना होगा।
यहाँ बहु-कथन 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
इनलाइन-टीवीएफ:
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
परिणाम 16,900 पंक्तियों को #Words
तालिका में डाला गया है ।
दो भिन्नताओं का परीक्षण करने के लिए, मैं 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, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0.
टेबल 'वर्कटेबल'। स्कैन काउंट 0, लॉजिकल
रीड्स 0, फिजिकल रीड्स 0, रीड- फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड- फॉरवर्ड रीड्स 0. टेबल '#स्क्रिप्ट'। स्कैन काउंट 1, लॉजिकल रीड 88, फिजिकल रीड्स 0, रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0।SQL सर्वर निष्पादन समय:
CPU समय = 1700 ms, बीता समय = 2022 ms।
SQL सर्वर पार्स और संकलित समय:
सीपीयू समय = 0 एमएस, बीता हुआ समय = 0 एमएस।
इनलाइन TVF:
तालिका 'संख्या'। स्कैन काउंट 1, लॉजिकल रीड 1272030, फिजिकल रीड्स 0, रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लोब रीड-फॉरवर्ड रीड्स 0.
टेबल 'वर्कटेबल'। स्कैन काउंट 0, लॉजिकल
रीड्स 0, फिजिकल रीड्स 0, रीड- फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड- फॉरवर्ड रीड्स 0. टेबल '#स्क्रिप्ट'। स्कैन काउंट 1, लॉजिकल रीड 88, फिजिकल रीड्स 0, रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0।SQL सर्वर निष्पादन समय:
CPU समय = 137874 ms, बीता समय = 139415 ms।
SQL सर्वर पार्स और संकलित समय:
सीपीयू समय = 0 एमएस, बीता हुआ समय = 0 एमएस।
निष्पादन योजनाएं इस तरह दिखती हैं:
इनलाइन वेरिएंट इस मामले में मल्टी-स्टेटमेंट वेरिएंट से इतना धीमा क्यों है?
@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, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0.
टेबल 'वर्कटेबल'। स्कैन काउंट 0, लॉजिकल
रीड्स 0, फिजिकल रीड्स 0, रीड- फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड- फॉरवर्ड रीड्स 0. टेबल '#स्क्रिप्ट'। स्कैन काउंट 1, लॉजिकल रीड्स 90, फिजिकल रीड्स 0, रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0।SQL सर्वर निष्पादन समय:
CPU समय = 1763 एमएस, बीता हुआ समय = 2192 एमएस।
dbo.FunctionIsPalindrome(w.Word)
:
(17424 पंक्ति) प्रभावित
'टेबल' वर्कटेबल । स्कैन काउंट 0, लॉजिकल रीड्स 0, फिजिकल रीड्स 0, रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0।
रीड्स फिजिकल रीड्स फॉरवर्ड रीड्स रीड्स रीड्स फॉरवर्ड रीड्स टेबल '#स्क्रिप्ट'। स्कैन काउंट 1, लॉजिकल रीड्स 90, फिजिकल रीड्स 0, रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0।SQL सर्वर निष्पादन समय:
CPU समय = 328 ms, बीता समय = 424 ms।
CROSS APPLY dbo.InlineIsPalindrome(w.Word) p
:
(१ Numbers४२४ पंक्ति) प्रभावित
'तालिका' संख्याएँ। स्कैन काउंट 1, लॉजिकल रीड 237100, फिजिकल रीड्स 0, रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0.
टेबल 'वर्कटेबल'। स्कैन काउंट 0, लॉजिकल
रीड्स 0, फिजिकल रीड्स 0, रीड- फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड- फॉरवर्ड रीड्स 0. टेबल '#स्क्रिप्ट'। स्कैन काउंट 1, लॉजिकल रीड्स 90, फिजिकल रीड्स 0, रीड-फॉरवर्ड रीड्स 0, लॉब लॉजिकल रीड्स 0, लॉब फिजिकल रीड्स 0, लॉब रीड-फॉरवर्ड रीड्स 0।SQL सर्वर निष्पादन समय:
CPU समय = 17737 ms, बीता समय = 17946 ms।
मैं SQL Server 2012 SP3, v11.0.6020, डेवलपर संस्करण पर यह परीक्षण कर रहा हूं।
यहां प्राथमिक कुंजी और क्लस्टर इंडेक्स के साथ मेरी संख्या तालिका की परिभाषा दी गई है:
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;