SQL 编译对 SQL Server 性能的影响有多大?

Ang*_*ker 24 performance sql-server-2005 sql-server perfmon

我正在分析 SQL Server 2005 的一个实例,通过 PerfMon 的SQLServer:SQL Statistics - SQL Compilations/sec指标,我看到平均值约为 170 左右。

我拿出 SQL Profiler 并寻找 SP:Compile 或 SQL:Compile 事件。显然它们不存在。我确实发现Stored Procedure/SP:RecompileTSQL/SQL:StmtRecompile事件。我在 Profiler 中看到的数据量表明这些是错误的事件,尽管我不确定。

所以我的问题。对其中任何一个的回答都会很棒。

  1. 如何查看 SQL Server 中编译的内容?
  2. 我是否选择了错误的指标来查看?在 Perfmon 或 SQL Profiler 中?
  3. 至于Stored Procedure/SP:RecompileTSQL/SQL:StmtRecompile事件在SQL事件探查器,他们不包括持续时间度量。如果这些事件无法查看对系统的时序影响,我该如何衡量这些事件对系统的影响。

Tho*_*ger 37

SQL Compilations/sec是一个很好的指标,但仅当与Batch Requests/sec结合使用时。就其本身而言,每秒编译数并不能真正告诉您太多信息。

您看到的是 170。如果每秒批处理请求仅为 200(效果有点夸张),那么是的,您需要深入了解原因(很可能是过度使用临时查询和一次性计划)。但是,如果您的批处理请求每秒大约为 5000,那么每秒 170 次编译也不错。一般的经验法则是Compilations/sec应为 10% 或小于总Batch Requests/sec

如果您真的想深入了解缓存的内容,请运行以下使用适当 DMV 的查询:

select
    db_name(st.dbid) as database_name,
    cp.bucketid,
    cp.usecounts,
    cp.size_in_bytes,
    cp.objtype,
    st.text
from sys.dm_exec_cached_plans cp
cross apply sys.dm_exec_sql_text(cp.plan_handle) st
Run Code Online (Sandbox Code Playgroud)

要获得所有一次性计划(计数):

;with PlanCacheCte as 
(
    select
        db_name(st.dbid) as database_name,
        cp.bucketid,
        cp.usecounts,
        cp.size_in_bytes,
        cp.objtype,
        st.text
    from sys.dm_exec_cached_plans cp
    cross apply sys.dm_exec_sql_text(cp.plan_handle) st
)
select count(*)
from PlanCacheCte
where usecounts = 1
Run Code Online (Sandbox Code Playgroud)

要获得与所有缓存计划相比,您拥有的一次性计数计划的比率:

declare @single_use_counts int, @multi_use_counts int

;with PlanCacheCte as 
(
    select
        db_name(st.dbid) as database_name,
        cp.bucketid,
        cp.usecounts,
        cp.size_in_bytes,
        cp.objtype,
        st.text
    from sys.dm_exec_cached_plans cp
    cross apply sys.dm_exec_sql_text(cp.plan_handle) st
    where cp.cacheobjtype = 'Compiled Plan'
)
select @single_use_counts = count(*)
from PlanCacheCte
where usecounts = 1

;with PlanCacheCte as 
(
    select
        db_name(st.dbid) as database_name,
        cp.bucketid,
        cp.usecounts,
        cp.size_in_bytes,
        cp.objtype,
        st.text
    from sys.dm_exec_cached_plans cp
    cross apply sys.dm_exec_sql_text(cp.plan_handle) st
    where cp.cacheobjtype = 'Compiled Plan'
)
select @multi_use_counts = count(*)
from PlanCacheCte
where usecounts > 1

select
    @single_use_counts as single_use_counts,
    @multi_use_counts as multi_use_counts,
    @single_use_counts * 1.0 / (@single_use_counts + @multi_use_counts) * 100
        as percent_single_use_counts
Run Code Online (Sandbox Code Playgroud)

至于通过 SQL Server 跟踪捕获的持续时间,它不适用于重新编译事件。看到计划编制所造成的持续时间或痛苦并不是那么重要,因为对于具体情况,您无能为力。解决方案是尝试通过计划重用(参数化查询、存储过程等)来限制编译和重新编译。


Jon*_*gel 11

应使用 PerfMon(或其他第 3 方解决方案)记录三个相关计数器。关键是要以某种方式记录这些统计数据。

  • SQL 统计信息\批处理请求数/秒
  • SQL 统计\SQL 编译/秒
  • SQL 统计\SQL 重新编译/秒

正如Thomas Stringer 提到的,关注编译/批处理请求的比率是很好的。显然,越低越好,但只有“好”的指导方针,只有您可以决定什么是可以接受的。您将通过减少编译数量看到的绝对性能增益量取决于许多因素。

我还喜欢查看重新编译/编译比率,以了解查询计划重用的数量。再次,越低越好。但是,在这种情况下,您确实希望在统计数据更改时在系统中进行重新编译(如果 DB 是只读的并且您进行了重新编译……可能有问题)。和我之前说的一样,只有“好”的指导方针。

您真正想要做的是随时间推移这些数字的趋势,因此,如果您看到任一比率出现大幅飙升,则表示部署了未正确使用查询计划的内容(理想情况下,这会在测试期间被捕获)——使用 Shark 的分析查询以找出罪魁祸首。此外,这里有一个可以找到经常重新编译的查询:

SELECT TOP 50
    qs.plan_generation_num,
    qs.execution_count,
    qs.statement_start_offset,
    qs.statement_end_offset,
    st.text
    FROM sys.dm_exec_query_stats qs
    CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
    WHERE qs.plan_generation_num > 1
    ORDER BY qs.plan_generation_num DESC
Run Code Online (Sandbox Code Playgroud)

如果您还记录 CPU 使用情况的统计数据,则可以将所有统计数据关联在一起,以确定它的伤害程度以及您的修复有多大帮助。在实践中,我发现即使是核心 sproc 上的一个糟糕的查询计划策略也会使服务器瘫痪;显然是YMMV。