0

我在 SQL Server 数据库中执行了以下查询。

SELECT * FROM Production.Product WHERE Name = 'Bearing Ball'

然后我尝试使用以下 SQL 命令获取查询文本以及统计信息:

    SELECT
    qs.sql_handle,
    qs.execution_count AS EXECUTION_COUNT,
    AVG_TIME = --Converted from microseconds
    (qs.total_elapsed_time/1000000) / qs.execution_count,
    qs.total_elapsed_time,
    TOTAL_TIME = --Converted from microseconds
    qs.total_elapsed_time/1000000,
    st.text AS TEXT
FROM
    sys.dm_exec_query_stats AS qs
        CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
        CROSS apply sys.dm_exec_query_plan (qs.plan_handle) AS qp
ORDER BY qs.total_worker_time DESC

我得到这样的东西

(@1 varchar(8000))SELECT * FROM [Production].[Product] WHERE [Name]=@1

但是,我想从我的 c# 程序中执行字符串匹配并获取查询文本的统计信息。c# 程序只知道原始查询(SELECT * FROM Production.Product WHERE Name = 'Bearing Ball')。被替换的参数不是唯一的问题,因为您可以看到数据库服务器在表名中添加了方括号。

有没有办法克服这个问题。如何将我的原始查询(SELECT * FROM Production.Product WHERE Name = 'Bearing Ball')转换为标准化查询((@1 varchar(8000))SELECT * FROM [Production].[Product] WHERE [Name]=@ 1)? 我可以使用 Microsoft.Data.Schema.ScriptDom 执行此操作吗?请注意,我想规范化我的查询而不在数据库服务器中执行它。

4

2 回答 2

0

可以使用 ScriptDom 规范化 T-SQL 代码。您需要在解析之前去掉前缀参数列表,因为 ScriptDom 只解析有效的 T-SQL。

然而,Microsoft.Data.Schema.ScriptDom 是一个旧版本,它随 Visual Studio 一起提供。自 SQL Server 2012 以来,SQL Server 本身附带了一个新版本。这有一个命名空间 Microsoft.SqlServer.TransactSql.ScriptDom 并与最新的 SQL 服务器版本保持同步。然而,对 ScriptDom 进行编程并非易事。规范化 T-SQL 代码是一项更加复杂的任务。Arvind Shyamsundar 在msdn 博客上发布了一篇关于该主题的博客. Arvind 演示的方法是规范化所有代码副本,然后对结果语句进行校验和,使用键的校验和将结果存储在字典中。如果校验和相同,则您的 T-SQL 必须与之前放入的相同。这个想法也适用于您,尽管可能并非 Arvind 演示中的所有规范化都对您的用例有用;您可能必须关闭一些,例如规范化文字值。

Arvind 在他的博客上附加了一个 zip,其中包含他的演示代码,因此您可以轻松地从那里开始。我在评论中要求 Arvind 在 GitHub 上发布他的代码,以便我们可以添加我们的扩展,但还没有收到他的消息。为了我自己的目的,我对 Arvind 的演示进行了扩展,以进行更多的规范化,例如消除多余的大括号、规范化布尔逻辑和规范化标量表达式。另外,我正在研究更多的规范化,比如规范化连接语句和连接子句。但这被证明是相当复杂的......我愿意分享我的代码,如果你认为你可以用它做点什么,请给我发消息。

于 2017-09-29T07:37:09.630 回答
0

一种解决方案,如果您只是希望能够将它们匹配起来,则可以在您的 SQL 语句的注释中添加 GUID 前缀,然后通过它进行匹配:

所以在 C# 中:

var statementMagicStringMarker = Guid.NewGuid().ToString("N");
cmd.CommandText = "--" + statementMagicStringMarker + "\n" +
"SELECT * FROM Production.Product WHERE Name = 'Bearing Ball'";
cmd.ExecuteNonQuery();

然后,当您运行统计查询时,查找包含您的 statementMagicStringMarker 的查询,您将知道您有相同的语句,即使它可能已被清理。通过使用 Guid.NewGuid() 你知道你会为每个查询获得一个唯一的标记,即使是从不同的客户端运行。

于 2017-01-30T02:05:57.067 回答