Switched From OPENXML to .nodes T(Item) // Performance is four times slower

  • I switched over a stored procedure FROM "OPENXML" to a more Sql Server 2005 syntax.

    My performance shot down 4-10 times. As in, a heck of alot slower.

    I created a small test, seen below. It performs about 3 times slower.

    Can anyone provide some insight to this?

    I've read a couple of places that OPENXML is not the preferred choice in SqlServer2005.

    http://blogs.sqlservercentral.com/michael_coles/archive/2008/01/20/stop-using-openxml-please.aspx

    for example.

    I wouldn't mind if it performed about the same. But ouch, its alot slower.

    I get the following results:

    OPENXML ms

    2360

    2005 Syntax ms

    6606

    As you can see, from this very simple test, the new syntax is 3X slower, on

    this very very very basic xml document. My xml is similar, 10 tables at 10

    rows max each. Overall size of the xml is <100KB.

    If you uncomment the following lines in (each of) the usp (stored

    procedures), you'll see they do EXACTLY the same thing.

    Just parse and push the data into some temp tables.

    /*

    --these are here just to show the parsing works..commented out.

    select * from @EmployeeUpdate

    select * from @DepartmentUpdate

    select * from @JobTitleUpdate

    select * from @EmployeeToJobTitleLinkUpdate

    */

    Here are 2 stored procedures, and the test code at the bottom. The xml is

    exactly the same.

    --TSQL START HERE

    print '[uspParseXmlWithOPENXML]'

    go

    IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[uspParseXmlWithOPENXML]') AND type in (N'P', N'PC'))

    DROP PROCEDURE [dbo].[uspParseXmlWithOPENXML]

    Go

    CREATE PROCEDURE [dbo].[uspParseXmlWithOPENXML] (

    @xml_doc TEXT

    )

    AS

    SET NOCOUNT ON

    DECLARE @hdoc INT -- handle to XML doc

    --Create an internal representation of the XML document.

    EXEC sp_xml_preparedocument @hdoc OUTPUT, @XML_Doc

    -- build a table (variable table) to store the xml-based result set

    DECLARE @EmployeeUpdate TABLE (

    EntryID int IDENTITY (1,1),

    EmployeeUUID uniqueidentifier,

    DepartmentUUID uniqueidentifier,

    LastName varchar(64) ,

    FirstName varchar(64) ,

    IsPermanent bit,

    HireDate smalldatetime

    ,AlreadyExists bit

    )

    DECLARE @DepartmentUpdate TABLE (

    EntryID int IDENTITY (1,1),

    DepartmentUUID uniqueidentifier,

    DepartmentName varchar(64)

    ,AlreadyExists bit

    )

    DECLARE @JobTitleUpdate TABLE (

    EntryID int IDENTITY (1,1),

    JobTitleUUID uniqueidentifier,

    JobTitleName varchar(64)

    ,AlreadyExists bit

    )

    DECLARE @EmployeeToJobTitleLinkUpdate TABLE (

    EntryID int IDENTITY (1,1),

    EmployeeUUID uniqueidentifier,

    JobTitleUUID uniqueidentifier

    )

    --the next call will take the info IN the @hdoc(with is the holder for @xml_doc), and put it IN a variableTable

    INSERT @EmployeeUpdate

    (

    EmployeeUUID,

    DepartmentUUID,

    LastName,

    FirstName,

    IsPermanent,

    HireDate

    ,AlreadyExists

    )

    SELECT

    EmployeeUUID,

    DepartmentUUID,

    LastName,

    FirstName,

    IsPermanent,

    HireDate

    , 0

    FROM

    OPENXML (@hdoc, '/OrganizationDS/Employee', 2) WITH (

    EmployeeUUID uniqueidentifier './EmployeeUUID' ,

    DepartmentUUID uniqueidentifier './DepartmentUUID' ,

    LastName varchar(64) './LastName' ,

    FirstName varchar(64) './FirstName' ,

    IsPermanent varchar(8) './IsPermanent' ,

    HireDate varchar(64) './HireDate'

    ,AlreadyExists bit

    )

    INSERT @DepartmentUpdate

    (

    DepartmentUUID,

    DepartmentName

    ,AlreadyExists

    )

    SELECT

    DepartmentUUID,

    DepartmentName

    , 0

    FROM

    OPENXML (@hdoc, '/OrganizationDS/Department', 2) WITH (

    DepartmentUUID uniqueidentifier './DepartmentUUID' ,

    DepartmentName varchar(64) './DepartmentName'

    ,AlreadyExists bit

    )

    INSERT @JobTitleUpdate

    (

    JobTitleUUID,

    JobTitleName

    ,AlreadyExists

    )

    SELECT

    JobTitleUUID,

    JobTitleName

    , 0

    FROM

    OPENXML (@hdoc, '/OrganizationDS/JobTitle', 2) WITH (

    JobTitleUUID uniqueidentifier './JobTitleUUID' ,

    JobTitleName varchar(64) './JobTitleName'

    ,AlreadyExists bit

    )

    INSERT @EmployeeToJobTitleLinkUpdate

    (

    EmployeeUUID ,

    JobTitleUUID

    )

    SELECT

    EmployeeUUID,

    JobTitleUUID

    FROM

    OPENXML (@hdoc, '/OrganizationDS/EmployeeToJobTitleLink', 2) WITH (

    EmployeeUUID uniqueidentifier './EmployeeUUID' ,

    JobTitleUUID uniqueidentifier './JobTitleUUID'

    )

    --Remove the handle to the XML document, since we're done with using the xmlDoc

    EXEC sp_xml_removedocument @hdoc

    /*

    --these are here just to show the parsing works..commented out.

    select * from @EmployeeUpdate

    select * from @DepartmentUpdate

    select * from @JobTitleUpdate

    select * from @EmployeeToJobTitleLinkUpdate

    */

    SET NOCOUNT OFF

    GO

    --GRANT EXECUTE ON dbo.uspParseXmlWithOPENXML TO northwinduser -- [[[[USERNAME]]]]

    GO

    print '[uspParseXmlWith2005Syntax]'

    go

    IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[uspParseXmlWith2005Syntax]') AND type in (N'P', N'PC'))

    DROP PROCEDURE [dbo].[uspParseXmlWith2005Syntax]

    Go

    CREATE PROCEDURE [dbo].[uspParseXmlWith2005Syntax] (

    @xml_doc xml

    )

    AS

    SET NOCOUNT ON

    -- build a table (variable table) to store the xml-based result set

    DECLARE @EmployeeUpdate TABLE (

    EntryID int IDENTITY (1,1),

    EmployeeUUID uniqueidentifier,

    DepartmentUUID uniqueidentifier,

    LastName varchar(64) ,

    FirstName varchar(64) ,

    IsPermanent bit,

    HireDate smalldatetime

    ,AlreadyExists bit

    )

    DECLARE @DepartmentUpdate TABLE (

    EntryID int IDENTITY (1,1),

    DepartmentUUID uniqueidentifier,

    DepartmentName varchar(64)

    ,AlreadyExists bit

    )

    DECLARE @JobTitleUpdate TABLE (

    EntryID int IDENTITY (1,1),

    JobTitleUUID uniqueidentifier,

    JobTitleName varchar(64)

    ,AlreadyExists bit

    )

    DECLARE @EmployeeToJobTitleLinkUpdate TABLE (

    EntryID int IDENTITY (1,1),

    EmployeeUUID uniqueidentifier,

    JobTitleUUID uniqueidentifier

    )

    --the next call will take the info IN the @hdoc(with is the holder for @xml_doc), and put it IN a variableTable

    INSERT @EmployeeUpdate

    (

    EmployeeUUID,

    DepartmentUUID,

    LastName,

    FirstName,

    IsPermanent,

    HireDate

    ,AlreadyExists

    )

    SELECT

    T.Item.value('EmployeeUUID[1]', 'UNIQUEIDENTIFIER') AS EmployeeUUID,

    T.Item.value('DepartmentUUID[1]', 'UNIQUEIDENTIFIER') AS DepartmentUUID,

    T.Item.value('LastName[1]', 'varchar(64)') AS LastName ,

    T.Item.value('FirstName[1]', 'varchar(64)') AS FirstName ,

    T.Item.value('IsPermanent[1]', 'bit') AS IsPermanent ,

    T.Item.value('HireDate[1]', 'smalldatetime') AS HireDate ,

    0

    FROM

    @xml_doc.nodes('/OrganizationDS/Employee') T(Item)

    INSERT @DepartmentUpdate

    (

    DepartmentUUID,

    DepartmentName

    ,AlreadyExists

    )

    SELECT

    T.Item.value('DepartmentUUID[1]', 'UNIQUEIDENTIFIER') AS DepartmentUUID,

    T.Item.value('DepartmentName[1]', 'varchar(64)') AS DepartmentName ,

    0

    FROM

    @xml_doc.nodes('/OrganizationDS/Department') T(Item)

    INSERT @JobTitleUpdate

    (

    JobTitleUUID,

    JobTitleName

    ,AlreadyExists

    )

    SELECT

    T.Item.value('JobTitleUUID[1]', 'UNIQUEIDENTIFIER') AS JobTitleUUID,

    T.Item.value('JobTitleName[1]', 'varchar(64)') AS JobTitleName ,

    0

    FROM

    @xml_doc.nodes('/OrganizationDS/JobTitle') T(Item)

    INSERT @EmployeeToJobTitleLinkUpdate

    (

    EmployeeUUID ,

    JobTitleUUID

    )

    SELECT

    T.Item.value('EmployeeUUID[1]', 'UNIQUEIDENTIFIER') AS EmployeeUUID,

    T.Item.value('JobTitleUUID[1]', 'UNIQUEIDENTIFIER') AS JobTitleUUID

    FROM

    @xml_doc.nodes('/OrganizationDS/EmployeeToJobTitleLink') T(Item)

    /*

    select * from @EmployeeUpdate

    select * from @DepartmentUpdate

    select * from @JobTitleUpdate

    select * from @EmployeeToJobTitleLinkUpdate

    */

    SET NOCOUNT OFF

    GO

    --GRANT EXECUTE ON dbo.uspParseXmlWith2005Syntax TO northwinduser -- [[[[USERNAME]]]]

    GO

    declare @TestLoopCounter int

    declare @msCheck int

    declare @compareDate datetime

    declare @NumberOfTestLoops int

    select @NumberOfTestLoops = 1000

    select @TestLoopCounter = @NumberOfTestLoops

    select @compareDate = getdate()

    while @TestLoopCounter > 0

    begin

    select @TestLoopCounter = @TestLoopCounter - 1

    exec uspParseXmlWithOPENXML

    '

    <OrganizationDS>

    <Employee>

    <EmployeeUUID>5F6892B7-9991-4CC4-9343-D4C1DE4E546C</EmployeeUUID>

    <DepartmentUUID>6893D100-0BA3-44B5-AAC2-E2E7294DB8C0</DepartmentUUID>

    <LastName>Smith</LastName>

    <FirstName>John</FirstName>

    <IsPermanent>true</IsPermanent>

    <HireDate>Apr 28 2008 10:04AM</HireDate>

    </Employee>

    <Department>

    <DepartmentUUID>6893D100-0BA3-44B5-AAC2-E2E7294DB8C0</DepartmentUUID>

    <DepartmentName>Department1</DepartmentName>

    </Department>

    <JobTitle>

    <JobTitleUUID>A893D100-0BA3-44B5-AAC2-E2E7294DB8CD</JobTitleUUID>

    <JobTitleName>JobTitle1</JobTitleName>

    </JobTitle>

    <EmployeeToJobTitleLink>

    <EmployeeUUID>5F6892B7-9991-4CC4-9343-D4C1DE4E546C</EmployeeUUID>

    <JobTitleUUID>A893D100-0BA3-44B5-AAC2-E2E7294DB8CD</JobTitleUUID>

    </EmployeeToJobTitleLink>

    </OrganizationDS>

    '

    end

    select @msCheck = datediff(ms , @compareDate , GETDATE())

    print 'OPENXML ms'

    print @msCheck

    print ''

    select @TestLoopCounter = @NumberOfTestLoops

    select @compareDate = getdate() --reset the date

    while @TestLoopCounter > 0

    begin

    select @TestLoopCounter = @TestLoopCounter - 1

    exec dbo.uspParseXmlWith2005Syntax

    '

    <OrganizationDS>

    <Employee>

    <EmployeeUUID>5F6892B7-9991-4CC4-9343-D4C1DE4E546C</EmployeeUUID>

    <DepartmentUUID>6893D100-0BA3-44B5-AAC2-E2E7294DB8C0</DepartmentUUID>

    <LastName>Smith</LastName>

    <FirstName>John</FirstName>

    <IsPermanent>true</IsPermanent>

    <HireDate>Apr 28 2008 10:04AM</HireDate>

    </Employee>

    <Department>

    <DepartmentUUID>6893D100-0BA3-44B5-AAC2-E2E7294DB8C0</DepartmentUUID>

    <DepartmentName>Department1</DepartmentName>

    </Department>

    <JobTitle>

    <JobTitleUUID>A893D100-0BA3-44B5-AAC2-E2E7294DB8CD</JobTitleUUID>

    <JobTitleName>JobTitle1</JobTitleName>

    </JobTitle>

    <EmployeeToJobTitleLink>

    <EmployeeUUID>5F6892B7-9991-4CC4-9343-D4C1DE4E546C</EmployeeUUID>

    <JobTitleUUID>A893D100-0BA3-44B5-AAC2-E2E7294DB8CD</JobTitleUUID>

    </EmployeeToJobTitleLink>

    </OrganizationDS>

    '

    end

    select @msCheck = datediff(ms , @compareDate , GETDATE())

    print '2005 Syntax ms'

    print @msCheck

    print ''

  • REMOVED: (Another poster showed me how to post xml code)

  • sholliday (4/28/2008)


    The forum isn't allowing me to put in xml tagged code into the post.

    So I posted the tsql test-it code here:

    http://www.ipass.net/sloan/code/OPENXML_vs_SQL2005Syntax_Test.txt

    ..

    If you want to post the XML - run a "find and replace" operation before pasting. You need to replace the brackets with the HTML "escaped" version. As in:

    replace <with &lt;

    replace > with &gt;

    Once you do that - your XML code should post just fine here.

    ----------------------------------------------------------------------------------
    Your lack of planning does not constitute an emergency on my part...unless you're my manager...or a director and above...or a really loud-spoken end-user..All right - what was my emergency again?

  • Microsoft SQL Server 2005 - 9.00.3042.00 (X64)

    Feb 10 2007 00:59:02

    Copyright (c) 1988-2005 Microsoft Corporation

    Standard Edition (64-bit) on Windows NT 5.2 (Build 3790: Service Pack 2)

    Microsoft SQL Server 2005 - 9.00.3054.00 (Intel X86)

    Mar 23 2007 16:28:52

    Copyright (c) 1988-2005 Microsoft Corporation

    Developer Edition on Windows NT 5.1 (Build 2600: Service Pack 2)

    Microsoft SQL Server 2005 - 9.00.3054.00 (Intel X86)

    Mar 23 2007 16:28:52

    Copyright (c) 1988-2005 Microsoft Corporation

    Enterprise Edition on Windows NT 5.2 (Build 3790: Service Pack 2)

    The versions I've gotten the crappy results on.

Viewing 4 posts - 1 through 3 (of 3 total)

You must be logged in to reply to this topic. Login to reply