以编程方式读取SQL Server的查询计划建议的SQL特定执行索引?

tbo*_*one 7 c# sql-server sqlclr sql-execution-plan

如果我在SSMS中运行此命令:

set showplan_xml on
GO
exec some_procedure 'arg1', 'arg2','arg3'
GO
set showplan_xml off
GO
Run Code Online (Sandbox Code Playgroud)

我获得了查询执行中涉及的完整调用堆栈的XML输出,以及任何建议的索引等.

怎么可能从C#中读到这个?

(一个用例可能是定期启用此功能并在生产环境中记录这些结果,以便密切关注索引建议.)

Sol*_*zky 9

在大多数情况下,这是两个独立的(虽然相关)问题.

是否有可能捕获或以某种方式获取缺失的索引信息?

  • 如果您想要建议的索引(并且不关心执行计划的其余部分),那么您可能最好使用与缺失索引关联的DMV.您只需要编写一些查询而不是应用程序代码.当然,只要服务重新启动,DMV信息就会重置,但如果您希望/需要保留历史记录,则可以将查询结果捕获到表中.有关完整详细信息,请参阅以下MSDN页面:

    我可以看到捕获执行计划以获取此信息的唯一好处是它将包含导致建议的查询文本,这显然非常适合进行该研究以确定要实现哪些索引,但也可能爆炸如果查询或查询的许多变体导致相同的建议索引,则数据行数.请记住一些事情.

  • 难道不是编程方式实现建议的指标.它们是供审查和考虑的.在那个时刻根据每个查询评估它们,并且不考虑:
    • 表上已有多少索引
    • 其他查询可能从类似的索引中受益(意味着,可能存在对任何单个查询都不明显的字段组合,但有助于3个或更多查询,因此只向表中添加一个索引而不是3个或更多个) .

是否有可能以编程方式捕获执行计划?

是的,这绝对可行,我自己也做过.无论是控制台应用程序,Windows窗体,Web应用程序,SQLCLR等,您都可以在.NET中执行此操作.

以下是您想要捕获XML计划时需要了解的详细信息:

  • XML执行计划是:
    • 作为单独的结果集发送
    • NVARCHAR/的数据类型发送string
    • 有两种类型:估计实际
  • 估计计划:
    • 就是这样:估计
    • 执行时返回: SET SHOWPLAN_XML ON;
    • 如果批处理中有多个查询,则仅返回包含多个查询的1个计划
    • 将返回简单查询的计划,例如SELECT 1DECLARE @Bob INT; SET @Bob = 52;
    • 不要执行任何查询.因此,此方法将返回单个结果集作为执行计划
  • 实际计划:
    • 是真正的交易,哟!
    • 执行时返回: SET STATISTICS XML ON;
    • 每个查询的 1个计划作为单独的结果集返回
    • 不会返回简单的查询,如计划SELECT 1DECLARE @Bob INT; SET @Bob = 52;
    • 执行批处理中的所有查询.因此,
      • 对于每个查询,此方法将返回一个两个结果集:如果查询返回数据,则查询结果将是第一个结果集,执行计划将是唯一的结果集(如果查询不返回数据) )或第二个结果集
      • 对于多个查询,执行计划将穿插任何查询结果.但是,由于某些查询不会返回任何结果,因此您无法简单地捕获每个其他结果集.我测试结果集中的单个字段,类型NVARCHAR,字段名称为Microsoft SQL Server 2005 XML Showplan(已经一致,至少通过SQL Server 2014;我还没有测试过SQL Server 2016).
      • 出于测试目的,您可能希望将这些查询包装在BEGIN TRAN;/中,COMMIT TRAN;以便不会发生实际的数据修改.
  • SET 命令需要在他们自己的批处理中,所以通过以下方式获取计划:

    SqlConnection _Connection = new sqlConnection(_ConnectionStringFromSomewhere);
    SqlCommand _Command = _Connection.CreateCommand();
    SqlDataReader _Reader = null;
    
    try
    {
      _Connection.Open();
    
      // SET command needs to be in its own batch
      _Command.CommandText = "SET something ON";
      _Command.ExecuteNonQuery();
    
      // Now we can run the desired query
      _Command.CommandText = _QueryToTest;
      _Reader = _Command.ExecuteReader();
    
      ..get you some execution plans!
    }
    finally
    {
      if (_Reader != null)
      {
        _Reader.Dispose();
      }
      _Command.Dispose();
      _Connection.Dispose();
    }
    
    Run Code Online (Sandbox Code Playgroud)

作为最后一点,我将提到,对于任何有兴趣捕获执行计划但对编写任何代码都不感兴趣的人,我已经将其实现为SQLCLR存储过程.该过程不仅获得XML执行计划,而且还获得来自STATISTICS TIME和的输出STATISTICS IO,当它们作为消息返回时更难捕获(就像PRINT语句一样).并且,可以将所有3种输出的结果捕获到表格中,以便在多次执行中进行进一步分析(方便进行当前和修订代码的A/B比较).这可以在SQL# SQLCLR库中找到(我也是作者).请注意,虽然有一个免费版本的SQL#,这个特定的存储过程,DB_GetQueryInfo仅在完整版中提供,而不是免费版.


更新:
有趣的是,我刚刚浏览了以下MSDN文章,该文章描述了如何使用SQLCLR获取估计的计划,提取估计的成本,将其作为SQLCLR存储过程的OUTPUT参数传回,然后根据那.我不认为我会将它用于这样的目的,但鉴于该文章是在2005年编写的,因此非常有趣:

在SQL Server 2005中使用SQLCLR处理XML Showplans

  • 优秀.你有一天应该写一本书! (3认同)