最快的方法从大量XML

时间:2015-10-13 08:22:56

标签: xml tsql sql-server-2012

我有大量(40万)大XML(200到4000行,有40个父子关系)。我想解析它们并收集它们中存在的所有节点。

使用XML

<tag1>
<tag2>
    <tag3>Content3</tag3>
</tag2>
<tag2>
    <tag4>Content4</tag4>
</tag2>
<tag2>
    <tag4>Content4</tag4>
</tag2>
<tag2>
    <tag5><tag6>Content6</tag6></tag5>
</tag2>
</tag1>

我想得到

tag1
tag1>tag2
tag1>tag2>tag3
tag1>tag2
tag1>tag2>tag4
tag1>tag2
tag1>tag2>tag4
tag1>tag2
tag1>tag2>tag5
tag1>tag2>tag5>tag6

或至少(除去叶子):

tag1
tag1>tag2
tag1>tag2
tag1>tag2
tag1>tag2
tag1>tag2>tag5

因为我的真正目标是检查节点,这些节点在目标数据库中被建模为表格。

输出可以是查询结果,表格或文件,我不介意。

最终目标是使用此数据来检查用于将XML内容加载到数据库中的SSIS是否未错过任何节点。事实上,我们知道它已经错过了一些,所以现在我们必须找到哪些。

我已检查过SQL Server 2012功能,但我有两个问题: - 它没有给我任何关于FILES性能的指针。我在使用文件时需要最快的方法,而不是在字符串中使用XML内容时 - 这有点麻烦

我已经用Qlikview做了我自己的解决方案,它检查可能的节点(我有XSD)是否在XML中并将结果输出到一个文件中,这很好但是太慢(每个XML 1到2个) ,太长了。)

谢谢你们!

1 个答案:

答案 0 :(得分:0)

我一直在寻找没有回答tsql / xml问题并找到你的问题。这让我很好奇,不知道今天是否有任何需要,但这是我的建议:

它适用于任何深度的XML ......

我必须承认,我通常不使用CURSOR,但在这种情况下我没有找到另一种方法。如果你不介意那么测试它的速度并给出简短的答案会很好 - 只是为了好奇: - )

    int corePoolSize = 400;
    int maximumPoolSize = 1_000_000;
    long keepaliveTimeout = 60L;
    TimeUnit keepaliveUnit = TimeUnit.SECONDS;
    BlockingQueue<Runnable> workQueue = new SynchronousQueue<Runnable>();

    ExecutorService cachedExecutor = new ThreadPoolExecutor(
            corePoolSize, 
            maximumPoolSize,
            keepaliveTimeout,
            keepaliveUnit,
            workQueue);

    ExecutorThreadPool threadpool = new ExecutorThreadPool(cachedExecutor);
    Server server = new Server(threadpool);

结果:

DECLARE @x XML=
'<tag1>
  <tag2>
    <tag3>Content3</tag3>
  </tag2>
  <tag2>
    <tag4>Content4</tag4>
  </tag2>
  <tag2>
    <tag4>Content4</tag4>
  </tag2>
  <tag2>
    <tag5>
      <tag6>Content6</tag6>
    </tag5>
  </tag2>
</tag1>';

CREATE TABLE #HelpTable(NodeIndex INT UNIQUE,NextNodeName VARCHAR(100),HasChildren BIT);
CREATE TABLE #FinalTags(ID INT IDENTITY,TagNames VARCHAR(1000));

WITH RootNode AS
(
    SELECT RN.value('local-name(.)','varchar(100)') AS RN_Name
          ,RN.query('.') AS RN_Node
    FROM @x.nodes('*') AS The(RN)
)
,AnalyzeNodes AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) * 10 AS NodeIndex 
          ,RN_Name
          ,TheNext.Nodes.value('local-name(.)','varchar(100)') AS NextNodeName
          ,CASE WHEN TheNext.Nodes.value('count(./*)','int')=0 THEN 0 ELSE 1 END AS HasChildren
    FROM RootNode
    CROSS APPLY RN_Node.nodes('//*') AS TheNext(Nodes)
) 

INSERT INTO #HelpTable
SELECT AnalyzeNodes.NodeIndex,AnalyzeNodes.NextNodeName,AnalyzeNodes.HasChildren
FROM AnalyzeNodes
UNION ALL
SELECT an.NodeIndex+1,RN_Name,1 
FROM AnalyzeNodes AS an
WHERE an.HasChildren=0

DECLARE @collect VARCHAR(1000)='';
DECLARE @tag VARCHAR(100);
DECLARE @children BIT;

DECLARE cur CURSOR FAST_FORWARD
FOR
    SELECT NextNodeName,HasChildren 
    FROM #HelpTable
    ORDER BY NodeIndex;

OPEN cur;

FETCH NEXT FROM cur INTO @tag,@children

WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO #FinalTags VALUES(@collect +  '>' + @tag);
    IF @children=0
        SET @collect='';
    ELSE
        SET @collect=@collect + '>' + @tag;

    FETCH NEXT FROM cur INTO @tag,@children
END

CLOSE cur;
DEALLOCATE cur;

SELECT SUBSTRING(TagNames,2,1000) AS TagNames
FROM #FinalTags
WHERE ID=1 OR TagNames<>(SELECT ft.TagNames FROM #FinalTags AS ft WHERE ft.ID=1)
ORDER BY ID,TagNames;

DROP TABLE #FinalTags;
DROP TABLE #HelpTable;