2016-09-16 51 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