将NVARCHAR值转换为XML的最快方法

时间:2016-05-26 15:24:08

标签: c# sql-server xml linq tsql

在我继承支持的数据库中,有几个表包含NVARCHAR(MAX)列,其中包含一小段非类型化XML数据。我的任务是搜索这些XML blob以获取对给定ID的引用,然后在找到第一个引用时停止并报告找到的内容。我正在循环遍历每一行,将blob转换为XML,然后使用XQuery在blob中搜索ID。

但是,由于表中的行数很多,因此NVARCHAR值初始转换为XML的时间过长。下面是我用来转换每个blob的代码示例,其中HistoryID是PK,值更改为从XMLData抓取下一个XML blob:

SELECT @XML = CONVERT(XML, XMLData)
FROM dbo.History
WHERE HistoryID = 1;

我也试图利用C#和LINQ,但XML blob太大而无法从.NET传递到SQL Server。不幸的是,我也无法在不破坏应用程序的情况下修改现有表。有没有更好的方法将这些XML blob变为可搜索的形式,或者我只是SOL?

3 个答案:

答案 0 :(得分:1)

SQL具有在数据库中处理XML的方式,例如值,存在,节点,查询和修改。然后,XML元素的value属性是可查询的。更多信息:https://www.simple-talk.com/sql/learn-sql-server/the-xml-methods-in-sql-server/

类似的东西:

SELECT 
CONVERT(XML, XMLData).value('(/Updated/UserId)[1]', 'int') AS UpdatedId 
FROM History
WHERE CONVERT(XML, XMLData).exist('(/Updated/UserId)[1]') > 0

如果某些xmldata blob大到360mb,那么必须尝试看看会发生什么......

为了提高性能,可以将XML索引(如果可以修改模式)添加到表https://msdn.microsoft.com/en-us/library/ms191497.aspx中。

答案 1 :(得分:0)

    // xmlElement is the column read from DB , consider having an index on the field as well as batching the reads if its too big   
    public static List<History> DeserializeHistory(XElement xmlElement)
    {

        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(List<History>));

        using (System.Xml.XmlReader reader = xmlElement.CreateReader())
        {

            return (List<History>)serializer.Deserialize(reader);

        }

    }

答案 2 :(得分:0)

不需要循环......试试这样

CREATE TABLE #tbl (ID INT,SomeColumn VARCHAR(100),YourXMLasString NVARCHAR(MAX));
INSERT INTO #tbl VALUES
 (1,'Test 11','<root><id>100</id><more>abc</more></root>')
,(2,'Test 12','<root><id>100</id><more>abc</more></root>')
,(3,'Test 21','<root><id>200</id><more>def</more></root>')
,(4,'Test 22','<root><id>200</id><more>def</more></root>')
,(5,'Test 23','<root><id>200</id><more>def</more></root>')
,(6,'Test  3','<root><id>300</id><more>ghi</more></root>');

--Just take the id 200
SELECT *
FROM #tbl
CROSS APPLY(SELECT CAST(YourXMLasString AS XML)) AS A(RealXml)
WHERE RealXml.exist('/root[id=200]') = 1

--Now stop at the first with 200
SELECT TOP 1 *
FROM #tbl
CROSS APPLY(SELECT CAST(YourXMLasString AS XML)) AS A(RealXml)
WHERE RealXml.exist('/root[id=200]') = 1
ORDER BY ID
GO

DROP TABLE #tbl;

一些提示

每当您搜索ID 时,您都会反复进行转换 ...当然快得多如果您存储转换后的XML

如果您更频繁地搜索相同的值,最好从XML中读取这些值并将其存储在专用的索引列中...

有了这个,您可以在现有表格中添加一列

ALTER TABLE #tbl ADD RealXml XML;
GO
UPDATE #tbl SET RealXml=CAST(YourXMLasString AS XML);
SELECT * FROM #tbl;

通过这个你可以创建一个边桌

CREATE TABLE #SideTable(RefID INT,RealXML XML);
INSERT INTO #SideTable
SELECT ID,CAST(YourXMLasString AS XML)
FROM #tbl;

SELECT * FROM #SideTable;

如果数据发生变化,您可能会考虑触发立即执行侧列/表的转换和更新。