FOR XML PATH性能改进挑战

时间:2017-10-20 21:52:20

标签: sql-server view query-performance correlated-subquery for-xml-path

我正在努力提高使用FOR XML PATH('')函数的20列的视图性能。该视图还使用非聚簇视图CTE,子查询和CAST函数调用其他字段,但此时我并不关心它们。

视图是非聚集视图,作业每隔5分钟选择一次,以向客户端应用程序显示新数据。所以底层源表每隔5分钟更新一次并插入一个井。

我已经在适当的地方创建了聚簇和非聚簇索引。在创建相应索引之前和之后测试源表上的各个视图组件并选择最佳路径。所以,我在索引方面做得很好。所有索引上的填充因子值都是100。

我的假设是查询速度慢了很多,因为我在视图中的20列上使用FOR 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;

我现在正在考虑将已被所有20列的FOR XML PATH('')函数字符串连接起来的缓存选项作为视图中的单独列,但需要不断更新(每5分钟一次)。

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

1 个答案:

答案 0 :(得分:0)

模糊的问题得到了模糊的答案,但现在就去了。

我同意似乎所有FOR XML连接可能都有所贡献(当然没有看到执行计划或完整的数据库架构,这几乎是我唯一要做的事情)。这里有很多未知因素可能会改变建议。如果您可以包含查询计划和IO统计信息,那将有所帮助。

我也没有声称具体知道为什么或者你是否需要在运行时使用视图或连接值,但这里有一些是探索性的问题:

  1. dbo.Table3中有多少行(与您连接值的基表?
  2. 每个MyConcatenatedId值中连接了多少行?
  3. 现在表现有多慢,需要多快?
  4. 这个视图大概每分钟/秒读取多少次?
  5. dbo.another-tbl似乎没有在提供的子查询中做任何事情(可能在真实版本中做了)。你需要吗?是否需要左连接?
  6. 我最初的想法是,如果这需要高效而不是,请不要使用视图。如果你必须使用一个视图,可以使用像NOEXPAND这样的索引提示。你有什么选择?

    不要序列化:我很难描绘需要在运行时序列化大量数据的场景。如果可能,返回数据集或在数据输入时序列化数据。

    • 赞成
      • 数据库端容易
    • 缺点
      • 可能无法满足您的需求

    持久表/提前工作:可能也需要触发器,但是当底层数据发生更改时,将其写入持久表,并从中读取。或者将Change Data Capture之类的更改排队,然后异步处理这些更改

    • 赞成
      • 快速阅读
    • 缺点
      • 维护和触发的痛苦可能增加繁重的开销

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

    • 赞成
      • 比视图更多可自定义以及您可以执行的更多优化
    • 缺点
      • 不能直接查询它们(虽然我认为这不是使用它们的好理由)