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

时间:2015-05-13 17:00:37

标签: 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

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

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

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

1 个答案:

答案 0 :(得分:9)

这在很大程度上是两个独立的(虽然是相关的)问题。

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

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

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

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

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

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

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

  • XML执行计划是:
    • 作为单独的结果集发送
    • NVARCHAR / string
    • 的数据类型发送
    • 有两种类型:估算实际
  • ESTIMATED 计划:
    • 只是:估计
    • 如果您执行:SET SHOWPLAN_XML ON; ,则会返回
    • 如果批次中有多个查询,则只返回包含多个查询的1个计划
    • 将返回简单查询的计划,例如SELECT 1DECLARE @Bob INT; SET @Bob = 52;
    • 执行 执行任何查询。因此,此方法将返回单个结果集作为执行计划
  • ACTUAL 计划:
    • 是真正的交易,哟!
    • 如果您执行:SET STATISTICS XML ON; ,则会返回
    • 将每个查询的计划作为单独的结果集
    • 返回
    • 返回简单查询的计划,例如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();
    }
    

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

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

Processing XML Showplans Using SQLCLR in SQL Server 2005