- 示例工程
- 数据库
- 教程
- 后端
【免费下载链接】sql-server-samples
Azure Data SQL Samples - Official Microsoft GitHub Repository containing code samples for SQL Server, Azure SQL, Azure Synapse, and Azure SQL Edge
SQL Assessment API 提供了一套可扩展的机制来评估 SQL Server 实例配置是否符合最佳实践。Performance probe(性能探针)是其中用于采集 Windows 性能计数器(Performance Counter)数据的核心探针类型,其返回的多条样本数据需要配合performance 数据变换(Data Transformation)计算平均值、比率、速率等派生值,最终由检查规则(Rule)的条件表达式判定合规性。读完本文,你将掌握 Performance probe 的完整 JSON 配置语法、计数器别名与实例过滤技巧、五种派生值函数的数学含义与适用场景,以及在同一检查中正确使用多个计数器并规避"多实例结果错位"陷阱的实战方案。
Performance probe 是什么
Performance probe 的类型代码(Type code)为Performance,用于读取目标机器上的性能计数器值(如Buffer Manager、Latches、Databases、Memory Node、Access Methods等性能对象下的计数器)。它并不是一个独立的检查,而是作为数据源供规则引用:探针负责"取数",performance 数据变换负责把多份样本"加工"成单个派生值,规则条件再基于该值做出合规性判断。
从 SQL Assessment API 的探针体系看,Performance是众多探针类型中的一种。在 Probe 文档 中列出的可用探针类型还包括 AzGraph、AzMetadata、CMD、External、PowerShell、Registry、SQL(T-SQL)与 WMI。其中 T-SQL 探针从动态管理视图(DMV)取数,而 Performance 探针与 WMI 探针一样,数据来自操作系统层,因此它适合捕捉 T-SQL 查询无法直接暴露的运行时指标,例如缓冲区命中率、闩锁等待时间、每秒事务数等。
samples/manage/sql-assessment-api/docs/Reference/Probes/Performance.mdImplementation 属性:采样频率与计数器清单
Performance probe 的implementation部分包含三个参数:
| 参数 | 是否必填 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
numberOfSamples | 可选 | number | 2 | 采集的样本数量 |
interval | 可选 | number | 1 | 两次采样之间的时间间隔(秒) |
counters | 必填 | object | — | 需要采集的性能计数器清单 |
- numberOfSamples:探针会对每个计数器连续采样 N 次。默认 2 次意味着拿到两个样本,足以支撑"差值型"派生值(如 rate、delta_ratio、ratio)的计算;某些场景(如求平均值)可提高采样次数以获得更稳定的统计结果。
- interval:相邻样本的采集间隔(秒)。默认 1 秒。对于瞬态波动明显的计数器(如
Pages Allocated/sec),合理调整采样间隔能反映更真实的负载特征。 - counters:必填。这是一个 JSON 对象,其每个属性名对应一个性能对象(Performance Object),例如
'Latches'、'Databases'、'Buffer Manager';每个性能对象的值又是一个 JSON 对象,其中的每个属性代表该对象下的一个性能计数器。
Performance probe 的整体结构可参考仓库中的结构图 BasicPerformanceProbeStructure.svg:
计数器别名与实例过滤
计数器名称常常包含空格和其他非字母数字字符(例如Pages Allocated/sec),无法直接在条件表达式和消息模板中引用。因此每个计数器都必须指定一个别名(alias)——别名将作为该计数器在检查条件与消息中使用的变量名。
此外,计数器可选地声明一个感兴趣的实例列表(instances)。例如 SQL Server 的Databases性能对象下,Transactions/sec计数器会为每个数据库实例分别报告值,其中_Total代表汇总实例;而Memory Node对象下的计数器则按 NUMA 内存节点实例报告。
示例一:最简单的单对象单计数器
下面的配置为Access Methods对象下的Pages Allocated/sec计数器采样,并把结果以pages_allocated变量提供给检查使用:
{ "type": "Performance", "implementation": { "Counters": { "Access Methods": { "Pages Allocated/sec": "pages_allocated" } } } }示例二:调整采样次数
为Memory Node对象下的Free Node Memory (KB)计数器只采集 1 个样本,此时该计数器只适合使用average、min、max这类不依赖多个样本的派生函数:
{ "type": "Performance", "implementation": { "NumberOfSamples": 1, "Counters": { "Memory Node": { "Free Node Memory (KB)": "free_node_memory" } } } }示例三:多对象、别名与实例过滤的组合
同时采集Memory Node与Access Methods两个性能对象;其中Free Node Memory (KB)通过对象式写法指定alias为free_node_memory,且instances限定为["000"](仅取编号为000的 NUMA 节点实例),而Target Node Memory (KB)则使用字符串简写形式:
{ "type": "Performance", "implementation": { "NumberOfSamples": 1, "Counters": { "Memory Node": { "Free Node Memory (KB)": { "alias": "free_node_memory", "instances": ["000"] }, "Target Node Memory (KB)": "target_node_memory" }, "Access Methods": { "Pages Allocated/sec": "pages_allocated" } } } }可见计数器值的两种写法等价:字符串简写("计数器名": "别名")与对象写法("计数器名": { "alias": "...", "instances": [...] })。需要过滤实例时使用对象写法。
完整 ruleset 示例:五个基于性能计数器的检查
下面是一份完整可用的规则集 JSON(与文档保持一致),它同时定义了 5 个针对Server目标的规则,以及一个名为PerformanceProbe的探针定义。通过这个例子可以完整看到"规则(rules)+ 探针(probes)+ 变换(transform)"三者如何协作:
{ "schemaVersion": "1.0", "name": "Performance Checks Example", "version": "1.0", "rules":[ { "target": { "type": "Server" }, "id": "TotalPages", "itemType": "definition", "displayName": "Buffer Manager Total pages", "description": "Use \"average\", \"min\", or \"max\" for counter type PERF_COUNTER_LARGE_RAWCOUNT(65792).", "message": "Total pages (@{total_pages}) is greater than 0", "condition": { "lt": ["@total_pages", 0] }, "probes": [ { "id": "PerformanceProbe", "transform": { "type": "performance", "counters": { "total_pages": "average" } } } ] }, { "target": { "type": "Server" }, "id": "CacheHitRatio", "itemType": "definition", "displayName": "Buffer Manager cache hit ratio", "description": "Use \"ratio\" for counter type PERF_LARGE_RAW_FRACTION(537003264) and specify base PERF_LARGE_RAW_BASE(1073939712).", "message": "Cache hit ratio (@{cache_hit_ratio:P0}) is greater than 0", "condition": { "lt": ["@cache_hit_ratio", 0] }, "probes": [ { "id": "PerformanceProbe", "transform": { "type": "performance", "counters": { "cache_hit_ratio": { "type": "ratio", "base": "cache_hit_ratio_base" } } } } ] }, { "target": { "type": "Server" }, "id": "LatchWaitTime", "itemType": "definition", "displayName": "Average Latch Wait Time", "description": "Use \"delta_ratio\" for counter type PERF_AVERAGE_BULK(1073874176) and base PERF_LARGE_RAW_BASE(1073939712).", "message": "Average Latch Wait Time (@{latch_wait_time}ms.) is greater than 0", "condition": { "lt": ["@latch_wait_time", 0] }, "probes": [ { "id": "PerformanceProbe", "transform": { "type": "performance", "counters": { "latch_wait_time": { "type": "delta_ratio", "base": "latch_wait_time_base" } } } } ] }, { "target": { "type": "Server" }, "id": "TransactionsPerSec", "itemType": "definition", "displayName": "Database Transactions per sec", "description": "Use \"rate\" for counter type PERF_COUNTER_BULK_COUNT(272696576).", "message": "Transactions per sec (@{transactions_sec:0.##}sec.) for database @{instance_name} is greater than 0", "condition": { "or": [{"eq": ["@instance_name", "_Total"]}, {"le": ["@transactions_sec", 0]}] }, "probes": [ { "id": "PerformanceProbe", "transform": { "type": "performance", "counters": { "transactions_sec": "rate" } } } ] }, { "target": { "type": "Server" }, "id": "TotalTransactionsPerSec", "itemType": "definition", "displayName": "Total Database Transactions per sec", "description": "Use \"rate\" for counter type PERF_COUNTER_BULK_COUNT(272696576).", "message": "Total Transactions per sec (@{transactions_sec:0.##}sec.) is greater than 0", "condition": { "lt": ["@transactions_sec", 0] }, "probes": [ { "id": "PerformanceProbe", "transform": { "type": "performance", "counters": { "transactions_sec": { "type": "rate", "instance": "_Total" } } } } ] } ], "probes":{ "PerformanceProbe": [{ "type": "Performance", "implementation": { "Counters": { "Buffer Manager": { "Buffer cache hit ratio": "cache_hit_ratio", "Buffer cache hit ratio base": "cache_hit_ratio_base", "Target pages": "total_pages" }, "Latches": { "Average Latch Wait Time (ms)": "latch_wait_time", "Average Latch Wait Time Base": "latch_wait_time_base" }, "Databases": { "Transactions/sec": "transactions_sec" } } } }] } }逐规则要点解读
- TotalPages:
Target pages属于PERF_COUNTER_LARGE_RAWCOUNT(65792)类型的原始计数值,适合用average(或min/max)派生;条件lt: ["@total_pages", 0]即"总页数小于 0 则告警"。 - CacheHitRatio:
Buffer cache hit ratio属于PERF_LARGE_RAW_FRACTION(537003264)比例型计数器,必须配套其 base 计数器Buffer cache hit ratio base(类型PERF_LARGE_RAW_BASE(1073939712)),在变换中使用ratio类型并指定base。消息模板@{cache_hit_ratio:P0}中的P0表示按百分比格式显示。 - LatchWaitTime:
Average Latch Wait Time (ms)属于PERF_AVERAGE_BULK(1073874176)平均型计数器,同样需要 base 计数器,使用delta_ratio类型派生。 - TransactionsPerSec:
Transactions/sec属于PERF_COUNTER_BULK_COUNT(272696576)速率型计数器,使用rate派生。由于它按数据库实例分别报告,条件用or组合:@instance_name等于_Total时跳过,或@transactions_sec <= 0时告警。@{transactions_sec:0.##}表示保留两位小数的数值格式。 - TotalTransactionsPerSec:在变换层用
instance: "_Total"直接过滤出汇总实例,条件只需比较单一值。
关于condition中使用的运算符(lt、or、eq、le等),可参考 Operators 参考文档,其中还包含match(正则匹配)、interval(区间取值)等更复杂的判定手段。规则的其他属性(message模板、displayName、description、itemType)的完整语义见 Rule 文档。
performance 数据变换:五种派生值函数
Performance probe 返回的是包含多次样本的表格,而检查需要一个派生值。performance变换(详见 DataTransformation/performance.md)为每个计数器计算指定的派生值。相关符号约定:
- n— 该计数器的样本数量
- c₁、c₂— 该计数器的样本值
- t₁、t₂— 样本的时间戳
- b₁、b₂— base 计数器的样本值
| 类型 | 参数 | 公式 | 适用计数器类型 |
|---|---|---|---|
average | — | (1/n) · Σcᵢ | PERF_COUNTER_LARGE_RAWCOUNT(65792)等原始计数值 |
delta_ratio | base_counter | (c₂ − c₁) / (b₂ − b₁) | PERF_AVERAGE_BULK(1073874176)(如平均闩锁等待时间),需配 base |
min/max | — | 所有样本的最小值 / 最大值 | 原始计数值,用于极值监控 |
rate | — | (c₂ − c₁) / (t₂ − t₁) | PERF_COUNTER_BULK_COUNT(272696576)(每秒计数类) |
ratio | base_counter | (c₂/b₂ + c₁/b₁) / 2 | PERF_LARGE_RAW_FRACTION(537003264)(如缓存命中率),需配 base |
要点:
- rate 与 average 的区别:
rate计算的是"两个样本的差值 ÷ 时间戳差值",即真正的每秒速率,适用于Transactions/sec这类本身就是"每秒次数"的计数器;average则是多个样本的算术平均,适用于静态量(如总页数)。 - ratio 与 delta_ratio 的区别:
ratio是两次采样的比值取平均;delta_ratio是两次采样差值的比值,两者都要求指定base计数器,且 base 计数器必须与主计数器同时出现在探针的Counters配置中(如示例中的Buffer cache hit ratio base)。 - 在
performance变换中指定派生类型有两种写法:字符串简写("total_pages": "average")或对象写法("cache_hit_ratio": { "type": "ratio", "base": "cache_hit_ratio_base" }),后者还可附加instance参数(如{ "type": "rate", "instance": "_Total" })在变换层过滤实例。
变换的整体结构见 BasicPerformanceTransformStructure.svg:
一个检查使用多个计数器:多实例结果的"错位"陷阱
在实际使用中,同一检查往往需要同时观察多个计数器(例如批量请求速率batch_request_sec与锁请求速率lock_requests_sec)。但当这些计数器来自不同的实例时,直接合并会得到意外结果。
看下面的反例:把两个计数器放进同一个 probe reference,batch_request_sec不指定实例,lock_requests_sec指定_Total:
"probes": [ { "id": "PerformanceProbe", "alias": "b", "transform": { "type": "performance", "counters": { "batch_request_sec": "rate", "lock_requests_sec": { "type": "rate", "instance": "_Total" } } } } ]变换结果返回两行数据,每行只填充了其中一个计数器的值:
| batch_request_sec | lock_requests_sec | instance_name |
|---|---|---|
| 123s | null | ''(未选择实例) |
| Null | 456s | '_Total' |
条件表达式是按行逐一求值的:第一行对batch_request_sec求值并可能触发一条消息,第二行对lock_requests_sec求值并触发另一个错误——这显然不符合"两个指标共同判定"的预期。
解决方案:用别名(alias)拆分引用
正确做法是将同一 Performance probe 引用两次,各自通过变换只取一个计数器,并用alias区分结果。alias是探针引用的任意别名,其机制详见 ProbeReference 文档中的 alias 一节:
"probes": [ { "id": "PerformanceProbe", "alias": "b", "transform": { "type": "performance", "counters": { "batch_request_sec": "rate" } } }, { "id": "PerformanceProbe", "alias": "l", "transform": { "type": "performance", "counters": { "lock_requests_sec": { "type": "rate", "instance": "_Total" } } } } ]此时传给检查的数据结构变为:
| b::batch_request_sec | b::instance_name | l::lock_requests_sec | l::instance_name |
|---|---|---|---|
| 123s | ''(无实例) | 456s | '_Total' |
两个计数器各自独立成行,条件可以同时、无歧义地引用它们。变量名有三种等价写法(在无歧义场景下):
@PerformanceProbe::batch_request_sec @b::batch_request_sec @batch_request_sec其中@b::batch_request_sec形式通过"别名 + 双冒号"精确定位到指定引用产生的数据,是处理"同一探针被多次调用"时的标准做法(ProbeReference 文档 中还有把探针 A 的数据作为参数传给探针 B 的进阶用法)。
引擎视角:Performance probe 的执行语义
了解探针引擎的执行语义有助于写出高效的规则。根据 Probe 文档 的说明:
- 探针是 JSON 属性,值为实现数组:属性名即探针 ID,值是一个探针实现(probe implementation)数组。引擎会选择第一个与目标模式(target pattern)匹配的实现,因此实现顺序很重要。Performance probe 也可以与其他类型的实现(如 T-SQL、WMI)混合构成一个探针。
- 探针应设计为无副作用(side-effect free)的函数:引擎不保证探针的调用顺序,甚至可能为降低对目标 SQL Server 的负载而重排调用;当没有任何检查需要某个探针的数据时,该探针根本不会被调用。默认规则集中的探针只读取元数据,不读取用户表数据,也不向实例写入任何内容。
- 性能计数器的采样开销:Performance probe 需要按
numberOfSamples × interval的时间窗口在目标机器上持续采样,这与其他一次性取数的探针(如单条 T-SQL 查询)不同。在自定义规则时,应合理控制采样次数与间隔,避免在高负载实例上叠加额外的采样开销。
与默认规则集的衔接
仓库中的 DefaultRuleset.csv 提供了默认规则集的可读版本(455 行规则,可直接在仓库中浏览与筛选),其中包含大量与性能相关的检查,例如:
HighCPUUsage:评估服务器整体 CPU 与 SQL Server 进程 CPU 占用(阈值参数默认 70);PlansUseRatio:评估计划缓存中单次使用计划的比例,用于判断是否应启用 "Optimize for ad hoc workloads";- 一系列 TempDB 文件配置检查(
TempDBFilesNotLess8、TempDBFiles1PerCPU等)。
这类运行时指标类检查正是 Performance probe 与 performance 变换的典型应用场景。读者可以结合 MakingCustomChecks_sample.json(自定义规则集示例)与 DisablingBuiltInChecks_sample.json(按 ID / 标签禁用内置规则示例)来编写自己的性能监控规则。更完整的概念体系(探针、规则、变换、消息模板、局部变量)可继续阅读 Customization 目录 下的文档。
小结
Performance probe 是 SQL Assessment API 中连接"操作系统性能计数器"与"配置合规性判定"的桥梁。本文覆盖了其三个 implementation 参数(numberOfSamples、interval、counters)、计数器别名与实例过滤的两种 JSON 写法、五种派生值函数(average、min/max、rate、ratio、delta_ratio)的公式与计数器类型对应关系,以及多计数器多实例场景下"按行求值"的陷阱与基于别名拆分的标准解法。在动手自定义性能规则时,建议对照 performance 数据变换文档 与 ProbeReference 文档 协同阅读,并结合默认规则集观察真实生产级规则的写法。
- 示例工程
- 数据库
- 教程
- 后端
【免费下载链接】sql-server-samples
Azure Data SQL Samples - Official Microsoft GitHub Repository containing code samples for SQL Server, Azure SQL, Azure Synapse, and Azure SQL Edge
相关推荐
SQL Assessment API 自定义探测指南:用 T-SQL Probe 驱动 SQL Server 配置评估
SQL Assessment API 自定义探测指南:用 T SQL Probe 驱动 SQL Server 配置评估 SQL Assessment API 通
示例工程数据库教程后端SQL Assessment API 深度指南:用规则集评估 SQL Server 与 Azure SQL 托管实例配置(sql-server-samples)
SQL Assessment API 深度指南:用规则集评估 SQL Server 与 Azure SQL 托管实例配置(sql server samples)
示例工程数据库教程后端sql-server-samples 实战指南:使用 SQL Assessment API 客户端评估 SQL Server 配置最佳实践
sql server samples 实战指南:使用 SQL Assessment API 客户端评估 SQL Server 配置最佳实践 SQL Assess
示例工程数据库教程后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考