在我继承支持的数据库中,有几个表包含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?
答案 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;
如果数据发生变化,您可能会考虑触发立即执行侧列/表的转换和更新。