Palindrome sorusundaki bazı cevapları ( cevabı sildiğimden sadece 10k + kullanıcı) karşılaştırarak kafa karıştırıcı sonuçlar alıyorum.
Standart bir işlevi çalıştırmaktan daha hızlı olacağını düşündüğüm çok ifadeli, şemaya bağlı bir TVF önerdim . Ayrıca, aşağıda göreceğiniz gibi, bu konuda yanlış olduğum halde, çoklu ifadeli TVF'nin "satır içi" olacağı izlenimindeydim. Bu soru, bu iki TVF stilinin performans farkı ile ilgilidir. İlk olarak, kodu görmeniz gerekir.
Çoklu ifade TVF'si:
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
Satır içi 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
Yukarıdaki fonksiyonun tablo olarak tarif edilir:
CREATE TABLE dbo.Numbers
(
Number INT NOT NULL
);
Not: Sayılar tablosunda dizin veya birincil anahtar yoktur ve 1.000.000 satır içerir.
Test yatağı geçici tablosu:
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;
Test sistemimde yukarıdaki tabloya INSERT
16.900 satır eklenir #Words
.
İki varyasyonu test etmek için, I SET STATISTICS IO, TIME ON;
ve aşağıdakileri kullanın:
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
Sürümün çok daha hızlı olmasını bekledim , ancak aşağıdaki sonuçlar bu varsayımı desteklemiyor.
Çok ifadeli TVF:
Tablo '# A1CE04C3'. Tarama sayısı 16896, mantıksal okuma 16900, fiziksel okuma 0, ileri okuma 0, lob mantık okuma 0, lob fiziksel okuma 0, lob okuma önceden 0 okur
. Tablo 'Çalışma masası'. Tarama sayısı 0, mantıksal okuma 0, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde 0 okuma
. Tablo '#Words'. Tarama sayısı 1, mantıksal okuma 88, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde okuma 0.SQL Server Yürütme Süreleri:
CPU süresi = 1700 ms, geçen süre = 2022 ms.
SQL Server ayrıştırma ve derleme zamanı:
CPU zamanı = 0 ms, geçen süre = 0 ms.
Satır içi TVF:
Tablo 'Sayılar'. Tarama sayısı 1, mantıksal okuma 1272030, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde 0 okuma
. Tablo 'Çalışma masası'. Tarama sayısı 0, mantıksal okuma 0, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde 0 okuma
. Tablo '#Words'. Tarama sayısı 1, mantıksal okuma 88, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde okuma 0.SQL Server Yürütme Süreleri:
CPU süresi = 137874 ms, geçen süre = 139415 ms.
SQL Server ayrıştırma ve derleme zamanı:
CPU zamanı = 0 ms, geçen süre = 0 ms.
Uygulama planları şöyle:
Bu durumda satır içi varyantı neden çoklu ifadeli varyanttan daha yavaş?
@AaronBertrand tarafından yapılan bir yoruma yanıt olarak, dbo.InlineIsPalindrome
işlevi CTE tarafından döndürülen satırları giriş sözcüğünün uzunluğuna uyacak şekilde sınırlamak için değiştirdim :
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'in önerdiği gibi, dbo.Numbers
tabloya birincil bir anahtar ve kümelenmiş dizin ekledim , bu da kesinlikle bir üretim ortamında görmeyi beklediğiniz şeylere yardımcı olur ve ona daha yakın olur.
Yukarıdaki testlerin yeniden çalıştırılması artık aşağıdaki istatistiklerle sonuçlanmaktadır:
CROSS APPLY dbo.IsPalindrome(w.Word) p
:
(17424 satır etkilendi)
Tablo '# B1104853'. Tarama sayısı 17420, mantıksal okuma 17424, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde 0 okuma
. Tablo 'Çalışma masası'. Tarama sayısı 0, mantıksal okuma 0, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde 0 okuma
. Tablo '#Words'. Tarama sayısı 1, mantıksal okuma 90, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma önceden okuma 0.SQL Server Yürütme Süreleri:
CPU süresi = 1763 ms, geçen süre = 2192 ms.
dbo.FunctionIsPalindrome(w.Word)
:
(17424 satır etkilendi)
Tablo 'Çalışma Masası'. Tarama sayısı 0, mantıksal okuma 0, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde 0 okuma
. Tablo '#Words'. Tarama sayısı 1, mantıksal okuma 90, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma önceden okuma 0.SQL Server Yürütme Süreleri:
CPU süresi = 328 ms, geçen süre = 424 ms.
CROSS APPLY dbo.InlineIsPalindrome(w.Word) p
:
(17424 satır etkilendi)
Tablo 'Sayılar'. Tarama sayısı 1, mantıksal okuma 237100, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde 0 okuma
. Tablo 'Çalışma masası'. Tarama sayısı 0, mantıksal okuma 0, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma öncesinde 0 okuma
. Tablo '#Words'. Tarama sayısı 1, mantıksal okuma 90, fiziksel okuma 0, okuma öncesi okuma 0, lob mantıksal okuma 0, lob fiziksel okuma 0, lob okuma önceden okuma 0.SQL Server Yürütme Süreleri:
CPU süresi = 17737 ms, geçen süre = 17946 ms.
Bunu SQL Server 2012 SP3, v11.0.6020, Developer Edition'da test ediyorum.
Birincil anahtar ve kümelenmiş dizin ile sayılarım tablosunun tanımı:
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;