Membandingkan beberapa jawaban pada pertanyaan Palindrome (hanya pengguna 10k +, karena saya telah menghapus jawabannya), saya mendapatkan hasil yang membingungkan.
Saya mengusulkan multi-pernyataan, skema-terikat TVF yang saya pikir akan lebih cepat daripada menjalankan fungsi standar, yang mana itu. Saya juga mendapat kesan bahwa TVF multi-pernyataan akan "digariskan", meskipun saya salah dalam hal itu, seperti yang akan Anda lihat di bawah. Pertanyaan ini adalah tentang perbedaan kinerja kedua gaya TVF. Pertama, Anda harus melihat kodenya.
Berikut ini adalah TVF multi-pernyataan:
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
The 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
The Numbers
tabel dalam fungsi di atas didefinisikan sebagai:
CREATE TABLE dbo.Numbers
(
Number INT NOT NULL
);
Catatan: Tabel angka tidak memiliki indeks dan tidak ada kunci utama, dan berisi 1.000.000 baris.
Meja sementara untuk tempat tidur:
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;
Pada sistem pengujian saya INSERT
hasil di atas dalam 16.900 baris dimasukkan ke dalam #Words
tabel.
Untuk menguji dua variasi, saya SET STATISTICS IO, TIME ON;
dan gunakan yang berikut ini:
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;
Saya berharap InlineIsPalindrome
versi ini secara signifikan lebih cepat, namun hasil berikut tidak mendukung anggapan itu.
TVF multi-pernyataan:
Tabel '# A1CE04C3'. Pindai hitungan 16896, bacaan logis 16900, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan lob baca-depan 0.
Tabel 'Meja Kerja'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca depan 0.
Tabel '#Words'. Pindai hitungan 1, bacaan logis 88, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.Waktu Eksekusi SQL Server:
Waktu CPU = 1700 ms, waktu yang berlalu = 2022 ms.
SQL Server mengurai dan mengkompilasi waktu:
Waktu CPU = 0 ms, waktu yang berlalu = 0 ms.
TVF sebaris:
Tabel 'Angka'. Pindai hitungan 1, bacaan logis 1272030, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan lob baca-depan 0.
Tabel 'Meja Kerja'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca depan 0.
Tabel '#Words'. Pindai hitungan 1, bacaan logis 88, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.Waktu Eksekusi SQL Server:
Waktu CPU = 137874 ms, waktu yang berlalu = 139415 ms.
SQL Server mengurai dan mengkompilasi waktu:
Waktu CPU = 0 ms, waktu yang berlalu = 0 ms.
Rencana eksekusi terlihat seperti:
Mengapa varian inline jauh lebih lambat daripada varian multi-pernyataan, dalam hal ini?
Menanggapi komentar oleh @AaronBertrand, saya telah memodifikasi dbo.InlineIsPalindrome
fungsi untuk membatasi baris yang dikembalikan oleh CTE agar sesuai dengan panjang kata input:
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)
);
Seperti yang disarankan @MartinSmith, saya telah menambahkan kunci utama dan indeks berkerumun ke dbo.Numbers
tabel, yang tentu saja membantu dan akan lebih dekat dengan apa yang diharapkan untuk dilihat dalam lingkungan produksi.
Menjalankan kembali tes di atas sekarang menghasilkan statistik berikut:
CROSS APPLY dbo.IsPalindrome(w.Word) p
:
(17424 baris terpengaruh)
Tabel '# B1104853'. Pindai menghitung 17420, bacaan logis 17424, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.
Tabel 'Meja Kerja'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca depan 0.
Tabel '#Words'. Pindai hitungan 1, bacaan logis 90, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.Waktu Eksekusi SQL Server:
Waktu CPU = 1763 ms, waktu yang berlalu = 2192 ms.
dbo.FunctionIsPalindrome(w.Word)
:
(17424 baris terpengaruh)
Tabel 'Meja Kerja'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca depan 0.
Tabel '#Words'. Pindai hitungan 1, bacaan logis 90, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.Waktu Eksekusi SQL Server:
Waktu CPU = 328 ms, waktu yang berlalu = 424 ms.
CROSS APPLY dbo.InlineIsPalindrome(w.Word) p
:
(17424 baris terpengaruh)
Tabel 'Angka'. Pindai hitungan 1, bacaan logis 237100, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.
Tabel 'Meja Kerja'. Pindai hitungan 0, bacaan logis 0, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bac baca baca depan 0.
Tabel '#Words'. Pindai hitungan 1, bacaan logis 90, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.Waktu Eksekusi SQL Server:
Waktu CPU = 17737 ms, waktu yang berlalu = 17946 ms.
Saya menguji ini pada SQL Server 2012 SP3, v11.0.6020, Edisi Pengembang.
Berikut adalah definisi tabel angka saya, dengan kunci utama dan indeks berkerumun:
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;