2016-09-16 48 views
1

我需要比较两个xml列。我目前有大约1000行数据,这是针对它,大约需要20分钟。无论如何,我可以改善这个查询运行速度。我该如何改进这个sql查询

SELECT 
    MAX(T.CaseName) AS CaseName, 
    T.PartNumber, 
    T.NodeName, 
    T.OldValue, 
    T.NewValue 
FROM (SELECT 
    C.CaseName, 
    old.N.value('../../../MaterialName[1]', 'nvarchar(100)') AS PartNumber, 
    old.N.value('Name[1]', 'nvarchar(4000)') AS NodeName, 
    old.N.value('Value[1]', 'nvarchar(4000)') AS OldValue, 
    new.N.value('Value[1]', 'nvarchar(4000)') AS NewValue 
FROM Cases c 
CROSS APPLY BomDataCase.nodes('/TopBomComponents/TopBomComponents/TopBomComponent/BomMaterials/BomMaterial/BomMaterialAttributes/CustomBomMaterialAttributes/CustomBomMaterialAttribute') AS old (N) 
CROSS APPLY BomDataChange.nodes('/TopBomComponents/TopBomComponents/TopBomComponent/BomMaterials/BomMaterial/BomMaterialAttributes/CustomBomMaterialAttributes/CustomBomMaterialAttribute') AS new (N) 
INNER JOIN LibraryStatuses ls 
    ON c.[Status] = ls.StatusId 
    AND c.LibraryId = ls.LibraryId 
WHERE old.N.value('../../../MaterialName[1]', 'nvarchar(100)') = new.N.value('../../../MaterialName[1]', 'nvarchar(100)') 
AND old.n.value('Name[1]', 'nvarchar(100)') = new.n.value('Name[1]', 'nvarchar(100)') 
AND old.n.value('Value[1]', 'nvarchar(100)') <> new.n.value('Value[1]', 'nvarchar(100)') 
AND ls.name = 'Review') AS T 
GROUP BY T.PartNumber, 
     T.NodeName, 
     T.OldValue, 
     T.NewValue 

每个xml字符串都相当大,大约有1000到1500行。

这是Cases表结构。

CREATE TABLE [dbo].[Cases](
    [CaseId] [int] IDENTITY(1,1) NOT NULL, 
    [LibraryId] [int] NOT NULL, 
    [CaseName] [nvarchar](500) NULL, 
    [ConfigId] [nvarchar](50) NOT NULL, 
    [CurrentConfigId] [nvarchar](50) NULL, 
    [PartNumber] [nvarchar](50) NOT NULL, 
    [Image] [nvarchar](250) NULL, 
    [Status] [int] NULL, 
    [Price] [decimal](18, 0) NULL, 
    [Comments] [nvarchar](500) NULL, 
    [Error] [nvarchar](max) NULL, 
    [LastRun] [datetime] NULL, 
    [LastRunApplication] [nvarchar](100) NULL, 
    [BomDataCase] [xml] NULL, 
    [BomDataChange] [xml] NULL, 
CONSTRAINT [PK_Cases] PRIMARY KEY CLUSTERED 
(
    [CaseId] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY] 
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] 

GO 
+0

请与SQL的味道标签这个。我假设这是SQL-Server。 – WillardSolutions

+0

也尝试提供示例表架构,索引。如果您可以提供repro可以有很大的帮助 – TheGameiswar

+0

我会发布这codereview。 http://codereview.stackexchange.com/questions/tagged/sql-server – scsimon

回答

1

这个答案来得太迟了,希望它仍然值得张贴...

读取XML应该做直线前进。什么是真正的沉重和昂贵的是向后导航,因为你这样做有../../..

这是更好地去完成一定的水平,从这个角度与APPLY继续。

没有见过真正的XML,这可能是不正确的,但你应该得到的想法:

SELECT 
    MAX(T.CaseName) AS CaseName, 
    T.PartNumber, 
    T.NodeName, 
    T.OldValue, 
    T.NewValue 
FROM (SELECT 
    C.CaseName, 
    old.mat.N.value('MaterialName[1]', 'nvarchar(100)') AS PartNumber, 
    old.N.value('Name[1]', 'nvarchar(4000)') AS NodeName, 
    old.N.value('Value[1]', 'nvarchar(4000)') AS OldValue, 
    new.N.value('Value[1]', 'nvarchar(4000)') AS NewValue 
FROM Cases c 
CROSS APPLY BomDataCase.nodes('/TopBomComponents/TopBomComponents/TopBomComponent/BomMaterials/BomMaterial') AS old (mat) 
CROSS APPLY old.mat.nodes('BomMaterialAttributes/CustomBomMaterialAttributes/CustomBomMaterialAttribute') AS old (N) 
CROSS APPLY BomDataChange.nodes('/TopBomComponents/TopBomComponents/TopBomComponent/BomMaterials/BomMaterial') AS new (mat) 
CROSS APPLY new.mat.nodes('BomMaterialAttributes/CustomBomMaterialAttributes/CustomBomMaterialAttribute') AS new (N) 
INNER JOIN LibraryStatuses ls 
    ON c.[Status] = ls.StatusId 
    AND c.LibraryId = ls.LibraryId 
WHERE mat.N.value('MaterialName[1]', 'nvarchar(100)') = mat.N.value('MaterialName[1]', 'nvarchar(100)') 
AND old.n.value('Name[1]', 'nvarchar(100)') = new.n.value('Name[1]', 'nvarchar(100)') 
AND old.n.value('Value[1]', 'nvarchar(100)') <> new.n.value('Value[1]', 'nvarchar(100)') 
AND ls.name = 'Review') AS T 
GROUP BY T.PartNumber, 
     T.NodeName, 
     T.OldValue, 
     T.NewValue