0

我正在改进使用FOR XML PATH('')函数使用20列的视图性能。该视图还调用其他字段使用非聚集视图CTE,子查询和CAST函数,但我现在不关心它们。FOR XML PATH性能改进挑战

该视图是一个非聚集视图,每5分钟由作业选择该视图以将新数据显示给客户端应用程序。因此底层源表格正在更新并每隔5分钟插入一个井。

我已经在适当的地方创建了群集和非群集索引。在创建相应索引之前对源表上的各个视图组件进行了测试,之后选择了最佳路由。所以,我在索引方面做得很好。在所有指标上,填充因子值几乎为100。

我的假设是,查询速度放缓了很多,因为我使用的针对20列XML PATH(“”)......

CREATE VIEW MyView 
AS 
col1, 
Col2, 
(SELECT CAST(Mytbl.[EmpId] AS NVARCHAR(50)) + '|' FROM MyDB.dbo.Mytbl_Optimized AS t1 (NOLOCK) 
      LEFT OUTER JOIN AnotherDB.dbo.Another-tbl AS t2 WITH (NOLOCK) 
      ON t1.EmpId = t2.EmpId 
WHERE AnotherDB.dbo.Table3.MyId = t1.MyId 
FOR XML PATH('')) AS MyConcatenatedID 
FROM AnotherDB.dbo.Table3 

我试图用它确定一个CASE语句如果每个列都带有FOR XML PATH('')任何要逐行连接的基础,然后仅当is有2个或更多个值连接到一个字符串时才使用FOR XML PATH('')。但正如我所期望的性能是可怕的......

,CASE 
     WHEN 
      (SELECT 
       LEN(EmpId) - LEN(REPLACE(EmpId, '|', '')) AS [CountOfConcatinated_EmpId] 
      FROM ISSearch..SearchBid WITH (NOLOCK) 
      ) > 1 -- this determis if values are concatenated or not. 
     THEN 
      (SELECT CAST(Mytbl.[EmpId] AS NVARCHAR(50)) + '|' FROM MyDB.dbo.Mytbl_Optimized AS t1 (NOLOCK) 
       LEFT OUTER JOIN AnotherDB.dbo.Another-tbl AS t2 WITH (NOLOCK) 
       ON t1.EmpId = t2.EmpId 
       WHERE AnotherDB.dbo.Table3.MyId = t1.MyId 
     FOR XML PATH('')) 

     ELSE 
      (SELECT CAST(Mytbl.[EmpId] AS NVARCHAR(50)) + '|' FROM MyDB.dbo.Mytbl_Optimized AS t1 (NOLOCK) 
       LEFT OUTER JOIN AnotherDB.dbo.Another-tbl AS t2 WITH (NOLOCK) 
       ON t1.EmpId = t2.EmpId 
       WHERE AnotherDB.dbo.Table3.MyId = t1.MyId) 
     END AS EmpId 
FROM AnotherDB.dbo.MyView; 

现在我考虑已经由FOR XML PATH(“”)的所有20列,在视图单独的列的函数字符串连接在一起的缓存选项,但需要不断更新(每5分钟)。

任何想法或替代解决方案?

+0

我假设'AnotherDB.dbo.Another-tbl作为t2'是一个虚拟名称,但那些需要离开连接(或在那里)?至少在提供的查询中,他们似乎没有做任何事情。我想知道一些其他的事情:1)有多少行被连接到'MyConcatednatedId'的每个值中2)在'Table3'中有多少行3)它现在的表现有多慢4)你有多快需要它? – Xedni

+0

使用[粘贴计划@ brentozar.com](https://www.brentozar.com/pastetheplan/)分享您的执行计划以下是说明:[如何使用粘贴计划](https://www.brentozar的.com/pastetheplan /指令/)。 – SqlZim

回答

0

模糊的问题会得到模糊的答案,但这里有。

我同意这似乎很可能所有的FOR XML串联可能是贡献(并且肯定没有看到一个执行计划或您的完整数据库模式,几乎我唯一要去)。这里有很多未知数可能会改变建议。如果你可以包含你的查询计划和IO统计数据,这将有所帮助。

我也不要求具体知道为什么,或者如果你需要使用一个视图或在运行时串联值,但有些这里有一些探索性的问题:

  1. 有多少行是dbo.Table3(基表反对,你会大约有多少串联值?
  2. 有多少行被串连到每个MyConcatenatedId价值?
  3. 它是如何现在正执行,以及如何快速它需要缓慢?
  4. 每分钟读取数/秒这是什么意思?
  5. dbo.another-tbl在提供的子查询中似乎没有做任何事情(也许它在真实版本中)。你需要吗?它是否需要成为左连接?

我最初的想法是,如果这需要高性能,而不是,不要使用视图。如果你必须使用视图,也许玩索引提示像NOEXPAND你有什么替代品?

不要序列化:我很难说明高容量数据需要在运行时序列化的场景。如果可能的话,返回的数据集或当它放在序列化数据。

  • 优点
    • 容易在DB侧
  • 缺点
    • 可能不适用于有可能你需要做什么

坚持的表格/尽早工作:可能也需要触发器,但是当底层数据发生变化时,将其写入持久表并从中读取。或者排队的改变类似Change Data Capture,那么这些变化异步工作

  • 优点
    • 快速从
  • 缺点阅读
    • 疼痛,保持和触发器可加繁重的开销

程序:除非您需要每次调用的所有数据,否则请考虑制作一个可以参数化的过程,以便只在需要时才提取所需的内容。一个视图仅限于一个查询,并且关于该复杂性的查询的统计信息可能很快变成垃圾。一个过程可以单独地将语句和更小的块分开,这样您可以更频繁地获得一致且更快的计划。

  • 优点
    • 更可自定义比视图和更优化的事情可以做
  • 缺点
    • 不能直接对它们进行查询(虽然我不认为这是不使用它们的好理由)