Sql 为什么拆分逗号分隔字符串的XML方法比传统的游标或WHILE循环方法花费更多的时间
我有一个表,有4列,其中一列是一个字符串,值用逗号分隔。我使用了两种方法以表格的形式拆分和扩展该列表: I方法>使用XML:Sql 为什么拆分逗号分隔字符串的XML方法比传统的游标或WHILE循环方法花费更多的时间,sql,sql-server-2008,sql-server-2008-r2,sql-server-2012,sqlxml,Sql,Sql Server 2008,Sql Server 2008 R2,Sql Server 2012,Sqlxml,我有一个表,有4列,其中一列是一个字符串,值用逗号分隔。我使用了两种方法以表格的形式拆分和扩展该列表: I方法>使用XML: declare @tbl TABLE ( id1 int, id2 int, id3 int, str1 varchar(255) ) INSERT INTO @tbl SELECT p.n.value('@id1','INT'), p.n.value('@releaseId','INT'), p.n.va
declare @tbl TABLE (
id1 int,
id2 int,
id3 int,
str1 varchar(255)
)
INSERT INTO @tbl
SELECT p.n.value('@id1','INT'), p.n.value('@releaseId','INT'), p.n.value('@id3','INT'), '', p.n.value('.','nvarchar(150)')
FROM (SELECT CAST(('<r id1="'+CAST(id1 AS varchar(20))+'" id2="'+CAST(id2 AS varchar(20))+'" id3="'+CAST(id3 AS varchar(20))+'">'+REPLACE(CAST(str1 AS nvarchar(MAX)), ',', '</r><r id1="'+CAST(id1 AS varchar(20))+'" id2="'+CAST(id2 AS varchar(20))+'" id3="'+CAST(id3 AS varchar(20))+'">')+'</r>') AS XML) AS x
FROM SomeTable WITH(NOLOCK) WHERE CAST(str1 AS nvarchar(MAX)) <> '') R
CROSS APPLY R.x.nodes('/r') p(n)
select * from @tbl
II进近>使用光标和WHILE循环方法
CREATE FUNCTION dbo.fnSplit(
@sInputList VARCHAR(MAX) -- List of delimited items
, @sDelimiter VARCHAR(8000) = ',' -- delimiter that separates items
) RETURNS @List TABLE (item VARCHAR(100))
BEGIN
DECLARE @sItem VARCHAR(8000)
WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
BEGIN
SELECT
@sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,@sInputList,0)-1))),
@sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,@sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))
IF LEN(@sItem) > 0
INSERT INTO @List SELECT @sItem
END
IF LEN(@sInputList) > 0
INSERT INTO @List SELECT @sInputList -- Put the last item in
RETURN
END
GO
-------------------------------------------
DECLARE @id1 INT
DECLARE @id2 INT
DECLARE @id3 INT
DECLARE @str1 nvarchar(MAX)
declare @tbl TABLE (
id1 int,
id2 int,
id3 int,
str1 varchar(255)
)
DECLARE getList CURSOR FOR
SELECT Id1, Id2, Id3, str1
FROM someTable
OPEN getaddUpdList
FETCH NEXT FROM getList INTO @id1, @id2, @id3, @str1
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO @tbl
SELECT @id1, @id2, @id3, '', _ID
FROM fnSplit(@str1, ',')
FETCH NEXT FROM getList INTO @id1, @id2, @id3, @sp, @str1
END
CLOSE getList
DEALLOCATE getList
select * from @tbl
正如我在网上读到的,任何地方都应该避免使用游标或WHILE循环。但在本例中,当我尝试上述两种方法时,I方法大约需要15-20秒,而II方法不到一秒。我不明白为什么会这样。我在SQLServer2008和2012上都尝试过,但结果是一样的
如果您能帮助理解这种不稳定的行为,我们将不胜感激。这个问题很久以前就提出了,但也许您会再次提出。简单的一点是,您误解了通过XML拆分字符串的方法。看看这个例子:
declare @tbl TABLE (
id1 int,
id2 int,
id3 int,
str1 varchar(255)
)
INSERT INTO @tbl VALUES
(1,2,3,'This,is,text,1')
,(10,20,30,'This,is,text,2')
,(100,200,300,'This,is,text,3')
,(1000,2000,3000,'This,is,text,4');
WITH Casted AS
(
SELECT id1
,id2
,id3
,CAST('<x>' + REPLACE(str1,',','</x><x>') + '</x>' AS XML) AS AsXml
FROM @tbl
)
SELECT id1,id2,id3
,The.Node.value('.','varchar(max)') AS splitvalue
FROM Casted
CROSS APPLY Casted.AsXml.nodes('/x') AS The(Node)
诀窍是,用结束和开始标记替换delimiter字符。开头的start标记和结尾的end标记允许字符串是部分XML。交叉应用程序调用nodes函数。value函数拾取当前节点的值,在本例中为唯一节点