我该如何改进这个SQL查询

时间:2016-09-16 15:39:05

标签: xml sql-server-2012

我需要比较两个xml列。我目前有大约1000行数据正在运行,大约需要20分钟。无论如何,我可以改进此查询以更快地运行。

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

1 个答案:

答案 0 :(得分: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