So I was doing some research on which is the best way to pass multiple-valued parameters into a stored procedure or user-defined function when I found some interesting results. I had always used a string-based user-defined function to parse a delimited list of values and I knew I could use XML to do the same thing, yet I had never compared the two side-by-side to see which is a better choice.
So which was faster? Well, using one of many available string-based UDFs, I had unexpected results. I thought that the XML version would be equivalent if not slower, but alas, I was wrong. The XML-based UDF consistently performed about 35% faster than the string-based inline table-valued UDF and about 65% faster than string-based table-valued UDF I tested.
I will be following-up this post soon with a post about various XML-based techniques that I tested…
One last item of note – this post was published (tags and all) from Word 2007.
As for now, here are the various functions used in the tests:
CREATE
FUNCTION dbo.fnString2IntList(@sData varchar(8000), @sDelim char(1))
RETURNS @tList TABLE
(ListValue int)
AS
BEGIN
DECLARE @sTemp int, @nPos int, @nPos2 int
IF
(Len(RTrim(LTrim(@sData)))
= 0)
RETURN
SET @nPos =
CharIndex(@sDelim, @sData, 1)
IF @nPos = 0 OR @nPos =
Len(@sData)
BEGIN
SET @sTemp =
CAST(SubString(@sData, 1,
(Len(@sData)
-
Sign(@nPos)))
as
int)
INSERT
INTO @tList VALUES(@sTemp)
RETURN
END
SET @sTemp =
CAST(SubString(@sData, 1, @nPos - 1)
as
int)
INSERT
INTO @tList VALUES(@sTemp)
WHILE @nPos > 0
BEGIN
SET @nPos2 =
CharIndex(@sDelim, @sData, @nPos + 1)
IF
(@nPos2 = 0)
SET @sTemp =
CAST(SubString(@sData, @nPos + 1,
Len(@sData))
as
int)
ELSE
SET @sTemp =
CAST(SubString(@sData, @nPos + 1,
ABS(@nPos2 - @nPos - 1))
as
int)
INSERT
INTO @tList VALUES(@sTemp)
SET @nPos =
CharIndex(@sDelim, @sData, @nPos + 1)
END
RETURN
END
GO
CREATE
FUNCTION dbo.fnString2IntList2(@sData varchar(8000), @sDelim char(1))
RETURNS
TABLE
AS
RETURN
(WITH csvtbl(i,j)
AS
(
SELECT i = 1, j =
CHARINDEX(@sDelim, @sData + @sDelim)
UNION
ALL
SELECT i = j + 1, j =
CHARINDEX(@sDelim, @sData + @sDelim, j + 1)
FROM csvtbl
WHERE
CHARINDEX(@sDelim, @sData + @sDelim, j + 1)
<> 0
)
SELECT
CAST(SUBSTRING(@sData, i, j - i)
as
int)
AS ListValue
FROM csvtbl)
GO
/* Assumes XML is as such
<list>
<i>1</i>
<i>23</i>
</list>
etc...
Uses minimal xml markup to keep input size as small as possible
*/
ALTER
FUNCTION dbo.fnXml2IntList(@xmlList xml)
RETURNS
TABLE
AS
RETURN
(SELECT tList.ListValue.value('.',
'int')
AS ListValue
FROM @xmlList.nodes('list/i')
AS tList(ListValue))
GO