USE tempdb go DROP DATABASE listmini go CREATE DATABASE listmini go USE listmini go CREATE TABLE Numbers (Number int NOT NULL PRIMARY KEY); go WITH digits (d) AS ( SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9 UNION SELECT 0) INSERT Numbers (Number) SELECT Number FROM (SELECT i.d + ii.d * 10 + iii.d * 100 + iv.d * 1000 + v.d * 10000 + vi.d * 100000 AS Number FROM digits i CROSS JOIN digits ii CROSS JOIN digits iii CROSS JOIN digits iv CROSS JOIN digits v CROSS JOIN digits vi) AS Numbers WHERE Number > 0 go CREATE FUNCTION fixstring_single(@str nvarchar(MAX), @itemlen tinyint) RETURNS TABLE RETURN(SELECT listpos = n.Number, str = rtrim(convert(nvarchar(4000), substring(@str, @itemlen * (n.Number - 1) + 1, @itemlen))) FROM Numbers n WHERE n.Number <= len(@str) / @itemlen + CASE len(@str) % @itemlen WHEN 0 THEN 0 ELSE 1 END) go CREATE TABLE Str_UNPACK (word nvarchar(50) NULL) go CREATE PROCEDURE FIX$SINGLE_Str_UNPACK_test @str nvarchar(MAX), @tookms int OUTPUT AS DECLARE @start datetime SELECT @start = getdate() INSERT Str_UNPACK(word) SELECT word = rtrim(a.str) FROM fixstring_single(@str, 30) AS a SELECT @tookms = datediff(ms, @start, getdate()); --SELECT word FROM Str_UNPACK TRUNCATE TABLE Str_UNPACK go SET NOCOUNT ON go -- This is the real test CREATE TABLE #fix (len int NOT NULL, ms int NOT NULL) DECLARE @len int, @sql nvarchar(MAX), @delta int SELECT @delta = 60000 SELECT @len = @delta WHILE @len <= 900000 BEGIN SELECT @sql = 'DECLARE @tookms int, @str nvarchar(MAX) SELECT @str = replicate(convert(nvarchar(MAX), ''X''), ' + ltrim(str(@len)) + ') EXEC FIX$SINGLE_Str_UNPACK_test @str, @tookms OUTPUT SELECT len(@str), @tookms' --PRINT @sql INSERT #fix(len, ms) EXEC(@sql) SELECT @len = @len + @delta END SELECT f1.len, f1.ms, msratio = convert(decimal(8, 2), 1E2*f1.ms/f2.ms - 100), lenratio = convert(decimal(8, 2), 1E2*f1.len/f2.len - 100) FROM #fix f1 LEFT JOIN #fix f2 ON f2.len = f1.len - @delta ORDER BY f1.len go DROP TABLE #fix