September 27, 2012 at 9:33 am
Hi,
In our invoice SP we pass the data as XML to send all the rows at once to the database.
To go through all the rows what's the best to use: OPENXML or nodes()?
I read some articles about the 1/8 memory used by sp_xml_preparedocument and to use ASAP sp_xml_removedocument.
Also OPENXML is better with long XML data and nodes for smaller one.
In any case if the XML data will be used more than once it should be stored in a table variable...
I created some test data to analyze the performance:
DECLARE @x XML = '<invoice><details><detail><product>1</product><qnt>3</qnt></detail><detail><product>2</product><qnt>2</qnt></detail><detail><product>4</product><qnt>3</qnt></detail><detail><product>10</product><qnt>3</qnt></detail><detail><product>21</product><qnt>3</qnt></detail><detail><product>31</product><qnt>3</qnt></detail><detail><product>33</product><qnt>3</qnt></detail></details></invoice>'
DECLARE @hnd INT
EXEC sp_xml_preparedocument @hnd OUTPUT, @x
INSERT INTO xmlTest SELECT ProductId, Quantity FROM OPENXML(@hnd, '/invoice/details/detail', 2) WITH (ProductId INT 'product', Quantity FLOAT 'qnt')
EXEC sp_xml_removedocument @hnd
GO
DECLARE @x XML = '<invoice><details><detail><product>1</product><qnt>3</qnt></detail><detail><product>2</product><qnt>2</qnt></detail><detail><product>4</product><qnt>3</qnt></detail><detail><product>10</product><qnt>3</qnt></detail><detail><product>21</product><qnt>3</qnt></detail><detail><product>31</product><qnt>3</qnt></detail><detail><product>33</product><qnt>3</qnt></detail></details></invoice>'
INSERT INTO xmlTest SELECT t.c.value('product[1]', 'INT') AS ProductId, t.c.value('qnt[1]', 'INT') AS Quantity FROM @x.nodes('/invoice/details/detail') t(c)
When running these two queries the Execution Plan says OPENXML takes 9% and nodes 91% of total time.
The statistics IO:
Table 'xmlTest'. Scan count 0, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 17, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(7 row(s) affected)
Table 'xmlTest'. Scan count 0, logical reads 7, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 2, logical reads 180, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(7 row(s) affected)
Apparently nodes is slower and has more reads...
I then, to test in a multi thread environment, used SQLQueryStress at http://www.datamanipulation.net/sqlquerystress/sqlquerystressdownload.asp.
I ran 10 iterations with 4 threads...
The 1st two times they both took the same time (11.6s, 12.8s)... But after that nodes took 7.8s and OPENXML kept taking 10 to 11sec.
My machine isn't a dedicated SQL Server, has other services and apps running (it's a developer's machine) and so I'm not sure these times are rigged...
Thanks,
Pedro
September 27, 2012 at 2:58 pm
Generally speaking I have found in the past that OPENXML is faster if you need all the XML. XQuery is faster when searching for a value within the XML (assuming proper XML indexes).
A.J.
DBA with an attitude
September 27, 2012 at 3:23 pm
A.J. Wilbur (9/27/2012)
Generally speaking I have found in the past that OPENXML is faster if you need all the XML. XQuery is faster when searching for a value within the XML (assuming proper XML indexes).
No searching... just "transforming" the XML into a table to process the details' data (in this case the invoice's lines).
OPENXML can be faster, in some case, but what about the "myth" (or not) about the 1/8 of memory used?!
Thanks,
Pedro
September 27, 2012 at 6:40 pm
I tried this simple test - on SQL 2012 Xquery wins - interesting to see if 2008 is the same.
-- Prepare some bigger XML data
DECLARE @xml XML
DECLARE @detail VARCHAR(4000) = '<detail><product>1</product><qnt>3</qnt></detail><detail><product>2</product><qnt>2</qnt></detail><detail><product>4</product><qnt>3</qnt></detail><detail><product>10</product><qnt>3</qnt></detail><detail><product>21</product><qnt>3</qnt></detail><detail><product>31</product><qnt>3</qnt></detail><detail><product>33</product><qnt>3</qnt></detail>'
DECLARE @details VARCHAR(MAX) = ''
SELECT @details = @detail + @details
FROM master..spt_values
WHERE spt_values.type='P'
SET @xml = '<invoice><details>' + @details + '</details></invoice>'
-- Use a dump variable to prevent returning data to the client
DECLARE @dump INT;
-- First test OpenXml
PRINT 'OPENXML'
PRINT '======='
SET STATISTICS IO ON ;
SET STATISTICS TIME ON;
DECLARE @hnd INT
EXEC sp_xml_preparedocument @hnd OUTPUT, @xml
SELECT @dump=ProductId, @dump=Quantity FROM OPENXML(@hnd, '/invoice/details/detail', 2) WITH (ProductId INT 'product', Quantity FLOAT 'qnt')
EXEC sp_xml_removedocument @hnd
SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;
-- Now XQuery with /text() which tends to be quicker
PRINT 'XQuery With /text()'
PRINT '==================='
SET STATISTICS IO ON ;
SET STATISTICS TIME ON;
SELECT @dump=t.c.value('(product/text())[1]', 'INT') , @dump=t.c.value('(qnt/text())[1]', 'INT') FROM @xml.nodes('/invoice/details/detail') t(c)
SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;
-- And finally XQuery without /text() - should be slower
PRINT 'XQuery'
PRINT '======'
SET STATISTICS IO ON ;
SET STATISTICS TIME ON;
SELECT @dump=t.c.value('product[1]', 'INT') , @dump=t.c.value('qnt[1]', 'INT') FROM @xml.nodes('/invoice/details/detail') t(c)
SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;
My results:
OPENXML
=======
SQL Server Execution Times:
CPU time = 172 ms, elapsed time = 167 ms.
SQL Server Execution Times:
CPU time = 483 ms, elapsed time = 490 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
XQuery With /text()
===================
SQL Server Execution Times:
CPU time = 203 ms, elapsed time = 200 ms.
XQuery
======
SQL Server Execution Times:
CPU time = 375 ms, elapsed time = 375 ms.
MM
select geometry::STGeomFromWKB(0x0106000000020000000103000000010000000B0000001000000000000840000000000000003DD8CCCCCCCCCC0840000000000000003DD8CCCCCCCCCC08408014AE47E17AFC3F040000000000104000CDCCCCCCCCEC3F9C999999999913408014AE47E17AFC3F9C99999999991340000000000000003D0000000000001440000000000000003D000000000000144000000000000000400400000000001040000000000000F03F100000000000084000000000000000401000000000000840000000000000003D0103000000010000000B000000000000000000143D000000000000003D009E99999999B93F000000000000003D009E99999999B93F8014AE47E17AFC3F400000000000F03F00CDCCCCCCCCEC3FA06666666666FE3F8014AE47E17AFC3FA06666666666FE3F000000000000003D1800000000000040000000000000003D18000000000000400000000000000040400000000000F03F000000000000F03F000000000000143D0000000000000040000000000000143D000000000000003D, 0);
September 28, 2012 at 2:44 am
Hi,
It's the same in 2008... nodes() with text() is twice as faster as simply nodes() and OPENXML...
Thanks for the tip... Even for large XML nodes() is faster.
Regards,
Pedro
September 28, 2012 at 3:14 am
mister.magoo (9/27/2012)
I tried this simple test - on SQL 2012 Xquery wins - interesting to see if 2008 is the same.
For small XML there's no difference. The 2nd Execution time on the OPENXML is how long the sp_xml_removedocument takes?! :w00t:
Thanks,
Pedro
September 28, 2012 at 3:23 am
PiMané (9/28/2012)
mister.magoo (9/27/2012)
I tried this simple test - on SQL 2012 Xquery wins - interesting to see if 2008 is the same.For small XML there's no difference. The 2nd Execution time on the OPENXML is how long the sp_xml_removedocument takes?! :w00t:
Thanks,
Pedro
Well, yes - the overhead of OPENXML has always been a sore point for me...
MM
select geometry::STGeomFromWKB(0x0106000000020000000103000000010000000B0000001000000000000840000000000000003DD8CCCCCCCCCC0840000000000000003DD8CCCCCCCCCC08408014AE47E17AFC3F040000000000104000CDCCCCCCCCEC3F9C999999999913408014AE47E17AFC3F9C99999999991340000000000000003D0000000000001440000000000000003D000000000000144000000000000000400400000000001040000000000000F03F100000000000084000000000000000401000000000000840000000000000003D0103000000010000000B000000000000000000143D000000000000003D009E99999999B93F000000000000003D009E99999999B93F8014AE47E17AFC3F400000000000F03F00CDCCCCCCCCEC3FA06666666666FE3F8014AE47E17AFC3FA06666666666FE3F000000000000003D1800000000000040000000000000003D18000000000000400000000000000040400000000000F03F000000000000F03F000000000000143D0000000000000040000000000000143D000000000000003D, 0);
September 28, 2012 at 4:16 am
mister.magoo (9/28/2012)
Well, yes - the overhead of OPENXML has always been a sore point for me...
Damn... that's a lot of time... probably related to the fact that's a big XML and creates data on tempdb...
It's a big overhead...
I read a lot about the 1/8 memory used by sp_xml_preparedocument but the truth is that I don't notice that... probably only on a multi thread environment this actually shows!!
I made a SQL restart and executed the OPENXML... SQL Server memory usage went up 11M.. I made another restart an executed the nodes() with text() and memory went up 8M... not a big difference... In both cases I waited a little time to see if SQL Server freed up memory but... SQL Server never frees memory 😛 .. It's like the alien plan of "Little Shop of Horrors".. "Feed me more...." 🙂
So my actual question is: for little XML since time is almost the same and sp_xml_removedocument doesn't take that much, should OPENXML be used or the memory is going to be a problem on a multi threaded environment?!
Thanks,
Pedro
September 28, 2012 at 4:27 am
PiMané (9/28/2012)
So my actual question is: for little XML since time is almost the same and sp_xml_removedocument doesn't take that much, should OPENXML be used or the memory is going to be a problem on a multi threaded environment?!Thanks,
Pedro
Whether OPENXML should be used or not is beyond my knowledge...
I personally never use it because I find the XML datatype to be more suited to my way of thinking and I have yet to see a situation in my own work where OPENXML would give me a benefit....
I wait with interest to hear from others on this...
MM
select geometry::STGeomFromWKB(0x0106000000020000000103000000010000000B0000001000000000000840000000000000003DD8CCCCCCCCCC0840000000000000003DD8CCCCCCCCCC08408014AE47E17AFC3F040000000000104000CDCCCCCCCCEC3F9C999999999913408014AE47E17AFC3F9C99999999991340000000000000003D0000000000001440000000000000003D000000000000144000000000000000400400000000001040000000000000F03F100000000000084000000000000000401000000000000840000000000000003D0103000000010000000B000000000000000000143D000000000000003D009E99999999B93F000000000000003D009E99999999B93F8014AE47E17AFC3F400000000000F03F00CDCCCCCCCCEC3FA06666666666FE3F8014AE47E17AFC3FA06666666666FE3F000000000000003D1800000000000040000000000000003D18000000000000400000000000000040400000000000F03F000000000000F03F000000000000143D0000000000000040000000000000143D000000000000003D, 0);
September 28, 2012 at 4:33 am
mister.magoo (9/28/2012)
I wait with interest to hear from others on this...
That make two of us 🙂
But honestly I don't think we'll have much feedback on this issue...
September 28, 2012 at 6:25 am
PiMané (9/28/2012)
mister.magoo (9/28/2012)
I wait with interest to hear from others on this...That make two of us 🙂
But honestly I don't think we'll have much feedback on this issue...
Oh, I don't know - there are plenty of folks around here who like a bit of performance testing...:-D
MM
select geometry::STGeomFromWKB(0x0106000000020000000103000000010000000B0000001000000000000840000000000000003DD8CCCCCCCCCC0840000000000000003DD8CCCCCCCCCC08408014AE47E17AFC3F040000000000104000CDCCCCCCCCEC3F9C999999999913408014AE47E17AFC3F9C99999999991340000000000000003D0000000000001440000000000000003D000000000000144000000000000000400400000000001040000000000000F03F100000000000084000000000000000401000000000000840000000000000003D0103000000010000000B000000000000000000143D000000000000003D009E99999999B93F000000000000003D009E99999999B93F8014AE47E17AFC3F400000000000F03F00CDCCCCCCCCEC3FA06666666666FE3F8014AE47E17AFC3FA06666666666FE3F000000000000003D1800000000000040000000000000003D18000000000000400000000000000040400000000000F03F000000000000F03F000000000000143D0000000000000040000000000000143D000000000000003D, 0);
March 17, 2016 at 7:35 am
When I want whole XML convert to tabular form I found OpenXML is easy and fast
😀
Viewing 12 posts - 1 through 11 (of 11 total)
You must be logged in to reply to this topic. Login to reply