Analisar dados de monitoramento do observador de banco de dados (preview)
Aplica-se a: Banco de Dados SQL do Azure Instância Gerenciada de SQL do Azure
Além de usar painéis no portal do Azure ou criar visualizações para exibir e analisar dados de monitoramento de SQL no Power BI, Grafana, Azure Data Explorer ou Análise em Tempo Real no Microsoft Fabric, você pode consultar seu armazenamento de dados de monitoramento diretamente.
Este artigo contém exemplos de consultas KQL e T-SQL que ajudam você a começar a analisar os dados de monitoramento coletados.
Usar KQL para analisar dados de monitoramento
Para analisar dados de monitoramento coletados, o método recomendado é usar a Linguagem de Consulta Kusto (KQL). A KQL é ideal para consultar telemetria, métricas e logs. Ela fornece amplo suporte para pesquisa e análise de texto, operadores e funções de séries temporais, análise e agregação e muitas outras construções de linguagem que facilitam a análise de dados.
A KQL é conceitualmente semelhante à SQL. Ela opera em entidades de esquema, como tabelas e colunas, e é compatível com operações relacionais, como projeto, restrição, ingresso e resumo, correspondendo às cláusulas SELECT
, JOIN
, WHERE
e GROUP BY
em SQL.
Para escrever e executar consultas KQL, você pode usar o Kusto Explorer ou a Interface do usuário da Web do Azure Data Explorer. O Kusto Explorer é um software de área de trabalho completo do Windows, enquanto a interface do usuário da Web do Azure Data Explorer permite executar consultas KQL e visualizar resultados no navegador em qualquer plataforma.
Você também pode usar essas ferramentas para consultar um banco de dados na Análise em Tempo real no Microsoft Fabric. Para se conectar, adicione uma nova conexão usando o URI de consulta do banco de dados da Análise em Tempo Real. Além disso, caso use a Análise em Tempo Real, você poderá analisar dados de monitoramento usando conjuntos de consultas KQL. Um conjunto de consultas KQL pode ser salvo como um artefato compartilhável do Fabric e usado para criar relatórios do Power BI.
Se você for novo em KQL, os seguintes recursos ajudam a começar:
- Escreva sua primeira consulta com a Linguagem de Consulta Kusto
- Início Rápido: consultar dados de amostra
- Tutorial: aprender operadores comuns
Os exemplos a seguir podem ajudar você a escrever suas próprias consultas KQL para exibir e analisar dados de monitoramento de SQL coletados. Você também pode usar esses exemplos como ponto de partida na criação de suas próprias visualizações de dados e painéis.
Usar a KQL para consultar o consumo de recursos ao longo do tempo
Neste exemplo, a consulta retorna métricas de consumo de recursos (CPU, trabalhos, produtividade de gravação de logs etc.) para a réplica primária de um banco de dados, um pool elástico ou uma instância gerenciada de SQL na última hora. Além de retornar o conjunto de resultados, ele o visualiza como um gráfico de tempo.
Neste e em outros exemplos, altere as variáveis nas instruções let para corresponder aos nomes do servidor, banco de dados, pool elástico ou instância gerenciada de SQL. Para usar um intervalo de tempo diferente, altere a variável duration
. Para obter mais informações, confira Literais de período de tempo.
let logicalServer = @"your-server-name";
let databaseName = @"your-database-name";
let replicaType = "Primary";
let duration = 1h;
sqldb_database_resource_utilization
| where sample_time_utc > ago(duration)
| where logical_server_name =~ logicalServer
| where database_name =~ databaseName
| where replica_type =~ replicaType
| project sample_time_utc,
avg_cpu_percent,
avg_instance_cpu_percent,
avg_data_io_percent,
avg_log_write_percent,
max_worker_percent
| sort by sample_time_utc desc
| render timechart;
Usar a KQL para exibir propriedades de banco de dados, pool elástico ou instância gerenciada de SQL
Neste exemplo, a consulta retorna um conjunto de todos os bancos de dados, pools elásticos ou instâncias gerenciadas de SQL das quais pelo menos uma amostra no conjunto de dados Propriedades correspondente foi coletada no último dia. Em outras palavras, cada linha representa um destino de monitoramento com suas propriedades observadas mais recentemente.
A função arg_max() agrega dados para retornar à linha mais recente para o conjunto especificado de colunas que identificam um destino. Por exemplo, para bancos de dados SQL do Azure, esse conjunto é logical_server_name
, database_name
, replica_type
.
let duration = 1d;
sqldb_database_properties
| where sample_time_utc > ago(duration)
| summarize arg_max(sample_time_utc, *) by logical_server_name, database_name, replica_type
| project-rename last_sample_time_utc = sample_time_utc
| sort by tolower(logical_server_name) asc,
tolower(database_name) asc,
case(
replica_type == "Primary", 0,
replica_type == "Geo-replication forwarder", 1,
replica_type == "Named secondary", 2,
replica_type == "HA secondary", 3,
4) asc;
Usar KQL para exibir estatísticas de runtime de consulta
Essa consulta retorna as principais consultas de consumo de recursos em sua propriedade de SQL do Azure. Altere uma variável para classificar consultas por qualquer métrica do Repositório de Consultas, incluindo tempo de CPU, tempo decorrido, contagem de execução etc. Você também pode definir variáveis para filtrar por um intervalo de tempo, tipo de execução de consulta e texto de consulta. Defina variáveis para se concentrar em um servidor lógico específico, pool elástico, instância gerenciada de SQL ou banco de dados.
A consulta usa o conjunto de dados de estatísticas de runtime da consulta para retornar o número de consultas principais que você especificar e inclui a classificação por todas as outras métricas de consumo de recursos.
let topQueriesBy = "cpu_time"; // Set to one of the following metrics to return the top resource consuming queries:
// count_executions, duration, cpu_time, logical_io_reads, logical_io_writes, physical_io_reads,
// num_physical_io_reads, clr_time, dop, query_max_used_memory, rowcount, log_bytes_used, tempdb_space_used
let topQueries = 10; // Set the number of top queries to return
let endTime = now();
let startTime = endTime - 1d;
let logicalServerName = @""; // Optionally filter by logical server name
let elasticPoolName = @""; // Optionally filter by elastic pool name, if any databases are in elastic pools
let databaseName = @""; // Optionally filter by database name
let executionType = ""; // Optionally filter by execution type. Use Regular, Aborted, Exception.
let queryHash = ""; // Optionally filter by query hash (example: 0xBAAA461A6C93EA88)
let queryTextFragment = ""; // Optionally filter by a query text fragment
sqldb_database_query_runtime_stats
| where interval_start_time >= startTime and interval_end_time <= endTime
| where isempty(executionType) or execution_type_desc =~ executionType
| where isempty(logicalServerName) or logical_server_name =~ logicalServerName
| where isempty(elasticPoolName) or elastic_pool_name =~ elasticPoolName
| where isempty(databaseName) or database_name =~ databaseName
| summarize dcount_logical_servers = dcount(logical_server_name),
any_logical_server_name = take_any(logical_server_name),
dcount_elastic_pools = dcount(strcat(logical_server_name, "|", elastic_pool_name)),
any_elastic_pool_name = take_any(elastic_pool_name),
dcount_databases = dcount(strcat(logical_server_name, "|", database_name)),
any_database_name = take_any(database_name),
dcount_sql_module_name = dcount(sql_module_name),
any_sql_module_name = take_any(sql_module_name),
dcount_context_settings_id = dcount(context_settings_id),
any_context_settings_id = take_any(context_settings_id),
query_sql_text = take_any(query_sql_text),
count_executions = sum(toreal(count_executions)),
count_successful_executions = sumif(toreal(count_executions), execution_type_desc == "Regular"),
count_aborted_executions = sumif(toreal(count_executions), execution_type_desc == "Aborted"),
count_exception_executions = sumif(toreal(count_executions), execution_type_desc == "Exception"),
duration_us = sum(avg_duration_us * count_executions),
cpu_time_us = sum(avg_cpu_time_us * count_executions),
logical_io_reads = sum(avg_logical_io_reads * count_executions),
logical_io_writes = sum(avg_logical_io_writes * count_executions),
physical_io_reads = sum(avg_physical_io_reads * count_executions),
num_physical_io_reads = sum(avg_num_physical_io_reads * count_executions),
clr_time_us = sum(avg_clr_time_us * count_executions),
dop = sumif(avg_dop * count_executions, is_parallel_plan),
query_max_used_memory = sum(avg_query_max_used_memory * count_executions),
rowcount = sum(avg_rowcount * count_executions),
log_bytes_used = sum(avg_log_bytes_used * count_executions),
tempdb_space_used = sum(avg_tempdb_space_used * count_executions)
by query_hash
| project logical_server_name = iif(dcount_logical_servers == 1, any_logical_server_name, strcat(any_logical_server_name, " (+", tostring(dcount_logical_servers - 1), ")")),
elastic_pool_name = iif(dcount_elastic_pools == 1, any_elastic_pool_name, strcat(any_elastic_pool_name, " (+", tostring(dcount_elastic_pools - 1), ")")),
database_name = iif(dcount_databases == 1, any_database_name, strcat(any_database_name, " (+", tostring(dcount_databases - 1), ")")),
query_sql_text,
count_executions,
count_successful_executions,
count_aborted_executions,
count_exception_executions,
duration_us,
cpu_time_us,
logical_io_reads,
logical_io_writes,
physical_io_reads,
num_physical_io_reads,
clr_time_us,
dop,
query_max_used_memory_kb = query_max_used_memory * 8,
rowcount,
log_bytes_used,
tempdb_space_used_kb = tempdb_space_used * 8,
sql_module_name = iif(dcount_sql_module_name == 1, any_sql_module_name, strcat(any_sql_module_name, " (+", tostring(dcount_sql_module_name - 1), ")")),
context_settings_id = iif(dcount_context_settings_id == 1, tostring(any_context_settings_id), strcat(any_context_settings_id, " (+", tostring(dcount_context_settings_id - 1), ")")),
query_hash
| sort by count_executions desc | extend count_executions_rank = row_rank_dense(count_executions)
| sort by duration_us desc | extend duration_rank = row_rank_dense(duration_us)
| sort by cpu_time_us desc | extend cpu_time_rank = row_rank_dense(cpu_time_us)
| sort by logical_io_reads desc | extend logical_io_reads_rank = row_rank_dense(logical_io_reads)
| sort by logical_io_writes desc | extend logical_io_writes_rank = row_rank_dense(logical_io_writes)
| sort by physical_io_reads desc | extend physical_io_reads_rank = row_rank_dense(physical_io_reads)
| sort by num_physical_io_reads desc | extend num_physical_io_reads_rank = row_rank_dense(num_physical_io_reads)
| sort by clr_time_us desc | extend clr_time_rank = row_rank_dense(clr_time_us)
| sort by dop desc | extend dop_rank = row_rank_dense(dop)
| sort by query_max_used_memory_kb desc | extend query_max_used_memory_rank = row_rank_dense(query_max_used_memory_kb)
| sort by rowcount desc | extend rowcount_rank = row_rank_dense(rowcount)
| sort by log_bytes_used desc | extend log_bytes_used_rank = row_rank_dense(log_bytes_used)
| sort by tempdb_space_used_kb desc | extend tempdb_space_used_rank = row_rank_dense(tempdb_space_used_kb)
| sort by case(
topQueriesBy =~ "count_executions", toreal(count_executions),
topQueriesBy =~ "duration", toreal(duration_us),
topQueriesBy =~ "cpu_time", toreal(cpu_time_us),
topQueriesBy =~ "logical_io_reads", toreal(logical_io_reads),
topQueriesBy =~ "logical_io_writes", toreal(logical_io_writes),
topQueriesBy =~ "physical_io_reads", toreal(physical_io_reads),
topQueriesBy =~ "num_physical_io_reads", toreal(num_physical_io_reads),
topQueriesBy =~ "clr_time", toreal(clr_time_us),
topQueriesBy =~ "dop", toreal(dop),
topQueriesBy =~ "query_max_used_memory", toreal(query_max_used_memory_kb),
topQueriesBy =~ "rowcount", toreal(rowcount),
topQueriesBy =~ "log_bytes_used", toreal(log_bytes_used),
topQueriesBy =~ "tempdb_space_used", toreal(tempdb_space_used_kb),
real(null)
) desc,
count_executions desc
| project-away count_executions
| where isempty(queryHash) or query_hash == queryHash
| where isempty(queryTextFragment) or query_sql_text contains queryTextFragment
| take topQueries;
Usar KQL para analisar contadores de desempenho ao longo do tempo
Neste exemplo, a consulta retorna valores de contador de desempenho para um intervalo de tempo que começa 30 minutos antes da hora de término especificada.
Este exemplo usa contadores de desempenho cumulativos, como Total request count
e Query optimizations/sec
. Cumulativo significa que o valor do contador continua aumentando à medida que a atividade de consulta SQL ocorre. A consulta neste exemplo calcula a diferença, ou delta, entre o valor do contador em cada amostra e seu valor na amostra anterior para obter o número de solicitações e otimizações que ocorreram desde a amostra anterior e, em seguida, visualiza essas métricas em um gráfico de tempo.
let logicalServer = @"your-server-name";
let databaseName = @"your-database-name";
let replicaType = "Primary";
let endTime = datetime("2023-12-19 22:10:00");
let startTime = endTime - 30m;
sqldb_database_performance_counters_common
| where sample_time_utc between (startTime .. endTime)
| where logical_server_name =~ logicalServer
| where database_name =~ databaseName
| where replica_type =~ replicaType
| where cntr_type == 272696576 // restrict to cumulative counters
| where object_name =~ "Workload Group Stats" and counter_name in ("Total request count","Query optimizations/sec")
| project replica_id, sample_time_utc, object_name, counter_name, cntr_value
| sort by replica_id asc, counter_name asc, sample_time_utc asc
| extend delta_cntr_value = iif(cntr_value >= prev(cntr_value) and counter_name == prev(counter_name) and replica_id == prev(replica_id), cntr_value - prev(cntr_value), real(null)),
delta_sample_time_utc = iif(sample_time_utc >= prev(sample_time_utc), datetime_diff("Millisecond", sample_time_utc, prev(sample_time_utc)), long(null))
| where isnotempty(delta_sample_time_utc)
| extend value = delta_cntr_value / delta_sample_time_utc * 1000
| summarize requests_per_sec = take_anyif(value, counter_name =~ "Total request count"),
query_optimizations_per_sec = take_anyif(value, counter_name =~ "Query optimizations/sec")
by sample_time_utc
| sort by sample_time_utc desc
| project sample_time_utc, requests_per_sec, query_optimizations_per_sec
| render timechart;
O exemplo a seguir é para contadores de desempenho em um ponto do tempo que relatam o valor observado mais recentemente, como Active memory grants count
, Pending memory grants count
e Processes blocked
. O intervalo de tempo são os últimos 30 minutos.
let logicalServer = @"your-server-name";
let databaseName = @"your-database-name";
let replicaType = "Primary";
let duration = 30m;
sqldb_database_performance_counters_common
| where sample_time_utc > ago(duration)
| where logical_server_name =~ logicalServer
| where database_name =~ databaseName
| where replica_type =~ replicaType
| where cntr_type == 65792 // restrict to point-in-time counters
| where (object_name =~ "General Statistics" and counter_name in ("Processes blocked"))
or
(object_name =~ "Resource Pool Stats" and counter_name in ("Active memory grants count","Pending memory grants count"))
| project sample_time_utc, counter_name, cntr_value
| render timechart;
O exemplo a seguir usa o conjunto de dados de contadores de desempenho (detalhados) para criar gráficos da utilização da CPU para pools de recursos de usuários e internos e grupos de carga de trabalho no Banco de Dados SQL do Azure. Para saber mais, confira Consumo de recursos por cargas de trabalho do usuário e processos internos.
As cargas de trabalho de usuário estão sendo executadas nos pools de recursos SloSharedPool1
ou UserPool
, enquanto todos os outros pools de recursos são usados para várias cargas de trabalho do sistema.
Da mesma forma, as cargas de trabalho do usuário estão sendo executadas nos grupos de carga de trabalho nomeados começando com UserPrimaryGroup.DBId
, enquanto todos os outros grupos de carga de trabalho são usados para várias cargas de trabalho do sistema. Por exemplo, as consultas de monitoramento do observador de banco de dados estão sendo executadas no grupo de carga de trabalho SQLExternalMonitoringGroup
.
let logicalServer = @"your-server-name";
let databaseName = @"your-database-name";
let replicaType = "Primary";
let endTime = datetime("2023-12-19 22:10:00");
let startTime = endTime - 30m;
sqldb_database_performance_counters_detailed
| where sample_time_utc between (startTime .. endTime)
| where logical_server_name =~ logicalServer
| where database_name =~ databaseName
| where replica_type =~ replicaType
| where cntr_type == 537003264 // restrict to ratio percentage counters
| where object_name =~ "Resource Pool Stats" and counter_name in ("CPU usage %")
| project sample_time_utc, resource_pool = instance_name, cpu_percentage = cntr_value
| render timechart;
let logicalServer = @"your-server-name";
let databaseName = @"your-database-name";
let replicaType = "Primary";
let endTime = datetime("2023-12-19 22:10:00");
let startTime = endTime - 30m;
sqldb_database_performance_counters_detailed
| where sample_time_utc between (startTime .. endTime)
| where logical_server_name =~ logicalServer
| where database_name =~ databaseName
| where replica_type =~ replicaType
| where cntr_type == 537003264 // restrict to ratio percentage counters
| where object_name =~ "Workload Group Stats" and counter_name in ("CPU usage %")
| project sample_time_utc, workload_group = instance_name, cpu_percentage = cntr_value
| render timechart;
Usar KQL para analisar esperas cumulativas ao longo do tempo
Este exemplo mostra como criar gráficos dos principais tipos de espera SQL em um intervalo de tempo. A consulta calcula o tempo de espera cumulativo para cada tipo de espera, em milissegundos por segundo de tempo decorrido. Você pode ajustar as variáveis de consulta para definir a hora de início e término do intervalo, o número dos principais tipos de espera a serem incluídos e a etapa entre os pontos de dados no gráfico.
A consulta usa duas técnicas para melhorar o desempenho:
- O operador KQL de partição com a estratégia
shuffle
para difundir o processamento de consultas por vários nós de cluster, se houver. - A função materialize() para persistir um conjunto de resultados intermediários que é reutilizado para calcular as principais esperas e criar a série temporal a ser traçada.
let logicalServer = @"your-server-name";
let databaseName = @"your-database-name";
let replicaType = "Primary";
let endTime = datetime("2023-12-19 22:10:00");
let startTime = endTime - 30m;
let top_wait_types = 10;
let chart_step = 30s;
let wait_type_sample = materialize (
sqldb_database_wait_stats
| where sample_time_utc between (startTime .. endTime)
| where logical_server_name =~ logicalServer
| where database_name =~ databaseName
| where replica_type =~ replicaType
| project replica_id, sample_time_utc, wait_type, wait_time_ms
| partition hint.strategy=shuffle by wait_type
(
sort by replica_id asc, sample_time_utc asc
| extend delta_wait_time_ms = iif(wait_time_ms >= prev(wait_time_ms) and replica_id == prev(replica_id), wait_time_ms - prev(wait_time_ms), long(null)),
delta_sample_time_utc = iif(sample_time_utc >= prev(sample_time_utc), datetime_diff("Millisecond", sample_time_utc, prev(sample_time_utc)), long(null))
| where isnotempty(delta_sample_time_utc)
| extend wait_ms_per_s = toreal(delta_wait_time_ms) / delta_sample_time_utc * 1000
| project sample_time_utc, wait_type, wait_ms_per_s
)
);
let top_wait = (
wait_type_sample
| summarize total_wait_ms_per_s = sum(wait_ms_per_s) by wait_type
| top top_wait_types by total_wait_ms_per_s desc
| project-away total_wait_ms_per_s
);
wait_type_sample
| join kind=inner top_wait on wait_type
| project-away wait_type1
| make-series wait_ms_per_s = avgif(wait_ms_per_s, isfinite(wait_ms_per_s)) default = long(null) on sample_time_utc from startTime to endTime step chart_step by wait_type
| project wait_type, sample_time_utc, wait_ms_per_s
| render timechart;
Usar T-SQL para analisar dados de monitoramento
Se você já está familiarizado com T-SQL, você pode começar a consultar e analisar dados de monitoramento de SQL imediatamente sem ter de aprender KQL. No entanto, a KQL é a linguagem recomendada para consultar dados no Azure Data Explorer ou na Análise em Tempo Real, pois fornece suporte incomparável para consultar dados telemétricos.
Você pode se conectar ao seu banco de dados do Azure Data Explorer ou da Análise em Tempo Real do SQL Server Management Studio (SSMS), do Azure Data Studio e de outras ferramentas comuns. Você pode consultar um Azure Data Explorer ou um banco de dados KQL como se fosse um SQL Server ou um banco de dados SQL do Azure. Para obter mais informações, confira Consultar dados no Azure Data Explorer usando uma emulação do SQL Server.
Observação
Nem todos os constructos T-SQL são compatíveis no Azure Data Explorer e na Análise em Tempo Real. Para obter detalhes, confira Consultar dados usando T-SQL.
A folha de referências de SQL para Linguagem de Consulta Kusto poderá ajudar você a traduzir suas consultas T-SQL para KQL se achar que o suporte a T-SQL é insuficiente para suas necessidades, ou se quiser converter suas consultas T-SQL em KQL para usar seus recursos de análise avançada.
Os exemplos a seguir mostram como consultar dados de monitoramento no armazenamento de dados do observador de banco de dados usando T-SQL.
Usar T-SQL para analisar o consumo de recursos ao longo do tempo
Neste exemplo, a consulta retorna métricas de consumo de recursos (CPU, trabalhos, produtividade de gravação de logs etc.) para a réplica primária de um banco de dados, um pool elástico ou uma instância gerenciada de SQL na última hora.
Neste e em outros exemplos, altere as variáveis na instrução DECLARE
para corresponder aos nomes do servidor, banco de dados, pool elástico ou instância gerenciada de SQL.
DECLARE @LogicalServerName sysname = 'your-server-name',
@DatabaseName sysname = 'your-database-name',
@ReplicaType sysname = 'Primary',
@DurationMinutes int = 60;
SELECT sample_time_utc,
avg_cpu_percent,
avg_instance_cpu_percent,
avg_data_io_percent,
avg_log_write_percent,
max_worker_percent
FROM sqldb_database_resource_utilization
WHERE sample_time_utc > DATEADD(minute, -@DurationMinutes, SYSUTCDATETIME())
AND
logical_server_name = @LogicalServerName
AND
database_name = @DatabaseName
AND
replica_type = @ReplicaType
ORDER BY sample_time_utc DESC;
Usar T-SQL para exibir propriedades de banco de dados, pool elástico ou instância gerenciada de SQL
Neste exemplo, a consulta retorna um conjunto de todos os bancos de dados, pools elásticos ou instâncias gerenciadas de SQL das quais pelo menos uma amostra no conjunto de dados de Propriedades correspondente foi coletada nas últimas 24 horas. Em outras palavras, cada linha representa um destino de monitoramento com suas propriedades observadas mais recentemente.
DECLARE @DurationHours int = 24;
SELECT p.sample_time_utc,
p.logical_server_name,
p.database_name,
p.replica_type,
p.database_id,
p.elastic_pool_name,
p.service_tier,
p.service_level_objective,
p.logical_cpu_count,
p.database_engine_memory_mb,
p.compatibility_level,
p.updateability,
p.database_engine_build_time,
p.database_engine_start_time_utc
FROM sqldb_database_properties AS p
INNER JOIN (
SELECT logical_server_name,
database_name,
replica_type,
MAX(sample_time_utc) AS last_sample_time_utc
FROM sqldb_database_properties
WHERE sample_time_utc > DATEADD(hour, -@DurationHours, SYSUTCDATETIME())
GROUP BY logical_server_name,
database_name,
replica_type
) AS ls
ON p.logical_server_name = ls.logical_server_name
AND
p.database_name = ls.database_name
AND
p.replica_type = ls.replica_type
AND
p.sample_time_utc = ls.last_sample_time_utc
WHERE p.sample_time_utc > DATEADD(hour, -@DurationHours, SYSUTCDATETIME())
ORDER BY LOWER(logical_server_name) ASC,
LOWER(database_name) ASC,
CASE replica_type
WHEN 'Primary' THEN 0
WHEN 'Geo-replication forwarder' THEN 1
WHEN 'Named secondary' THEN 2
WHEN 'HA secondary' THEN 3
END ASC;
Usar T-SQL para visualizar estatísticas de runtime de consulta
Essa consulta retorna as principais consultas de consumo de recursos em sua propriedade de SQL do Azure. Altere a variável @TopQueriesBy
para localizar as principais consultas por qualquer métrica do Repositório de Consultas, incluindo tempo de CPU, tempo decorrido, contagem de execução etc. Você também pode definir variáveis para filtrar por um intervalo de tempo, tipo de execução de consulta e hash de consulta de uma consulta específica, ou para se concentrar em bancos de dados de um servidor lógico específico, pool elástico ou instância gerenciada de SQL.
A consulta usa o conjunto de dados de estatísticas de runtime da consulta para retornar as principais consultas especificadas. Também retorna sua classificação por todas as outras métricas de consumo de recursos.
DECLARE @EndTime datetime2 = SYSUTCDATETIME(),
@StartTime datetime2 = DATEADD(hour, -24, SYSUTCDATETIME()),
/*
Set the next variable to one of the following metrics to return the top resource consuming queries:
executions, cpu_time, duration, logical_io_reads, physical_io_reads, num_physical_io_reads,
clr_time, query_max_used_memory, log_bytes_used, tempdb_space_used, row_count, dop
*/
@TopQueriesBy varchar(30) = 'cpu_time',
@TopQueries int = 10,
@LogicalServerName sysname = '', -- Optionally filter by logical server name
@ElasticPoolName sysname = '', -- Optionally filter by elastic pool name, if any databases are in elastic pools
@DatabaseName sysname = '', -- Optionally filter by database name
@ExecutionType varchar(30) = '', -- Optionally filter by execution type. Use Regular, Aborted, Exception.
@QueryHash varchar(18) = ''; -- Optionally filter by query hash (example: 0xBAAA461A6C93EA88)
SELECT TOP (@TopQueries)
CONCAT(logical_server_name, IIF(count_logical_servers > 1, CONCAT(' (+', CAST(count_logical_servers - 1 AS varchar(11)), ')'), '')) AS logical_server_name,
CONCAT(database_name, IIF(count_databases > 1, CONCAT(' (+', CAST(count_databases - 1 AS varchar(11)), ')'), '')) AS database_name,
query_sql_text,
CONCAT(CAST(query_id AS varchar(11)), IIF(count_queries > 1, CONCAT(' (+', CAST(count_queries - 1 AS varchar(11)), ')'), '')) AS query_id,
CONCAT(CAST(plan_id AS varchar(11)), IIF(count_plans > 1, CONCAT(' (+', CAST(count_plans - 1 AS varchar(11)), ')'), '')) AS plan_id,
regular_executions,
aborted_executions,
exception_executions,
cpu_time_us,
duration_us,
logical_io_reads,
physical_io_reads,
num_physical_io_reads,
clr_time_us,
query_max_used_memory_kb,
log_bytes_used,
tempdb_space_used_kb,
row_count,
dop,
query_hash,
executions_rank,
cpu_time_rank,
duration_rank,
logical_io_reads_rank,
physical_io_reads_rank,
num_physical_io_reads_rank,
clr_time_rank,
query_max_used_memory_rank,
log_bytes_used_rank,
tempdb_space_used_rank,
row_count_rank,
dop_rank
FROM (
SELECT *,
DENSE_RANK() OVER (ORDER BY executions DESC) AS executions_rank,
DENSE_RANK() OVER (ORDER BY cpu_time_us DESC) AS cpu_time_rank,
DENSE_RANK() OVER (ORDER BY duration_us DESC) AS duration_rank,
DENSE_RANK() OVER (ORDER BY logical_io_reads DESC) AS logical_io_reads_rank,
DENSE_RANK() OVER (ORDER BY physical_io_reads DESC) AS physical_io_reads_rank,
DENSE_RANK() OVER (ORDER BY num_physical_io_reads DESC) AS num_physical_io_reads_rank,
DENSE_RANK() OVER (ORDER BY clr_time_us DESC) AS clr_time_rank,
DENSE_RANK() OVER (ORDER BY query_max_used_memory_kb DESC) AS query_max_used_memory_rank,
DENSE_RANK() OVER (ORDER BY log_bytes_used DESC) AS log_bytes_used_rank,
DENSE_RANK() OVER (ORDER BY tempdb_space_used_kb DESC) AS tempdb_space_used_rank,
DENSE_RANK() OVER (ORDER BY row_count DESC) AS row_count_rank,
DENSE_RANK() OVER (ORDER BY dop DESC) AS dop_rank
FROM (
SELECT query_hash,
COUNT(DISTINCT(logical_server_name)) AS count_logical_servers,
MAX(logical_server_name) AS logical_server_name,
COUNT(DISTINCT(database_name)) AS count_databases,
MAX(database_name) AS database_name,
COUNT(DISTINCT(query_id)) AS count_queries,
MAX(query_id) AS query_id,
COUNT(DISTINCT(plan_id)) AS count_plans,
MAX(plan_id) AS plan_id,
MAX(query_sql_text) AS query_sql_text,
SUM(IIF(execution_type_desc = 'Regular', count_executions, 0)) AS regular_executions,
SUM(IIF(execution_type_desc = 'Aborted', count_executions, 0)) AS aborted_executions,
SUM(IIF(execution_type_desc = 'Exception', count_executions, 0)) AS exception_executions,
SUM(count_executions) AS executions,
SUM(avg_cpu_time_us * count_executions) AS cpu_time_us,
SUM(avg_duration_us * count_executions) AS duration_us,
SUM(avg_logical_io_reads * count_executions) AS logical_io_reads,
SUM(avg_physical_io_reads * count_executions) AS physical_io_reads,
SUM(avg_num_physical_io_reads * count_executions) AS num_physical_io_reads,
SUM(avg_clr_time_us * count_executions) AS clr_time_us,
SUM(avg_query_max_used_memory * count_executions) * 8 AS query_max_used_memory_kb,
SUM(avg_log_bytes_used * count_executions) AS log_bytes_used,
SUM(avg_tempdb_space_used * count_executions) * 8 AS tempdb_space_used_kb,
SUM(avg_rowcount * count_executions) AS row_count,
SUM(IIF(is_parallel_plan = 1, avg_dop * count_executions, NULL)) AS dop
FROM sqldb_database_query_runtime_stats
WHERE interval_start_time >= @StartTime AND interval_end_time <= @EndTime
AND
(@ExecutionType = '' OR LOWER(execution_type_desc) = LOWER(@ExecutionType))
AND
(@LogicalServerName = '' OR LOWER(logical_server_name) = LOWER(@LogicalServerName))
AND
(@ElasticPoolName = '' OR LOWER(elastic_pool_name) = LOWER(@ElasticPoolName))
AND
(@DatabaseName = '' OR LOWER(database_name) = LOWER(@DatabaseName))
GROUP BY query_hash
) AS rsa
) AS rsar
WHERE @QueryHash = '' OR LOWER(query_hash) = LOWER(@QueryHash)
ORDER BY CASE @TopQueriesBy
WHEN 'executions' THEN executions_rank
WHEN 'cpu_time' THEN cpu_time_rank
WHEN 'duration' THEN duration_rank
WHEN 'logical_io_reads' THEN logical_io_reads_rank
WHEN 'physical_io_reads' THEN physical_io_reads_rank
WHEN 'num_physical_io_reads' THEN num_physical_io_reads_rank
WHEN 'clr_time' THEN clr_time_rank
WHEN 'query_max_used_memory' THEN query_max_used_memory_rank
WHEN 'log_bytes_used' THEN log_bytes_used_rank
WHEN 'tempdb_space_used' THEN tempdb_space_used_rank
WHEN 'row_count' THEN row_count_rank
WHEN 'dop' THEN dop_rank
END ASC;
Usar T-SQL para analisar contadores de desempenho ao longo do tempo
Neste exemplo, a consulta retorna valores de contador de desempenho para os últimos 30 minutos.
Este exemplo usa contadores de desempenho cumulativos, como Total request count
e Query optimizations/sec
. Cumulativo significa que o valor do contador continua aumentando à medida que a atividade de consulta ocorre. A consulta usa a função analítica LAG() para calcular a diferença, ou delta, entre o valor do contador em cada amostra e seu valor na amostra anterior para obter o número de solicitações e otimizações que ocorreram desde a amostra anterior.
DECLARE @LogicalServerName sysname = 'your-server-name',
@DatabaseName sysname = 'your-database-name',
@ReplicaType sysname = 'Primary',
@DurationMinutes int = 30;
SELECT sample_time_utc,
SUM(IIF(
counter_name = 'Total request count',
CAST((cntr_value - prev_cntr_value) AS decimal) / DATEDIFF(millisecond, prev_sample_time_utc, sample_time_utc) * 1000,
NULL
)) AS requests_per_second,
SUM(IIF(
counter_name = 'Query optimizations/sec',
CAST((cntr_value - prev_cntr_value) AS decimal) / DATEDIFF(millisecond, prev_sample_time_utc, sample_time_utc) * 1000,
NULL
)) AS query_optimizations_per_second
FROM (
SELECT sample_time_utc,
LAG(sample_time_utc) OVER (PARTITION BY replica_id, object_name, counter_name ORDER BY sample_time_utc ASC) AS prev_sample_time_utc,
counter_name,
cntr_value,
LAG(cntr_value) OVER (PARTITION BY replica_id, object_name, counter_name ORDER BY sample_time_utc ASC) AS prev_cntr_value
FROM sqldb_database_performance_counters_common
WHERE sample_time_utc > DATEADD(minute, -@DurationMinutes, SYSUTCDATETIME())
AND
logical_server_name = @LogicalServerName
AND
database_name = @DatabaseName
AND
replica_type = @ReplicaType
AND
cntr_type = 272696576 /* restrict to cumulative counters */
AND
object_name = 'Workload Group Stats'
AND
counter_name IN ('Total request count','Query optimizations/sec')
) AS pc
WHERE cntr_value >= prev_cntr_value
AND
sample_time_utc >= prev_sample_time_utc
GROUP BY sample_time_utc
ORDER BY sample_time_utc DESC;
Usar T-SQL para analisar contadores de desempenho em um ponto no tempo
O próximo exemplo é para contadores de desempenho em um ponto no tempo que relatam o valor observado mais recentemente, como Active memory grants count
, Pending memory grants count
e Processes blocked
.
DECLARE @LogicalServerName sysname = 'your-server-name',
@DatabaseName sysname = 'your-database-name',
@ReplicaType sysname = 'Primary',
@DurationMinutes int = 30;
SELECT sample_time_utc,
SUM(IIF(
counter_name = 'Processes blocked',
cntr_value,
NULL
)) AS processes_blocked,
SUM(IIF(
counter_name = 'Active memory grants count',
cntr_value,
NULL
)) AS active_memory_grants,
SUM(IIF(
counter_name = 'Pending memory grants count',
cntr_value,
NULL
)) AS pending_memory_grants
FROM (
SELECT sample_time_utc,
counter_name,
cntr_value
FROM sqldb_database_performance_counters_common
WHERE sample_time_utc > DATEADD(minute, -@DurationMinutes, SYSUTCDATETIME())
AND
logical_server_name = @LogicalServerName
AND
database_name = @DatabaseName
AND
replica_type = @ReplicaType
AND
cntr_type = 65792 /* restrict to point-in-time counters */
AND
(
(object_name = 'General Statistics' AND counter_name IN ('Processes blocked'))
OR
(object_name = 'Resource Pool Stats' AND counter_name IN ('Active memory grants count','Pending memory grants count'))
)
) AS pc
GROUP BY sample_time_utc
ORDER BY sample_time_utc DESC;
Usar T-SQL para analisar esperas cumulativas ao longo do tempo
Neste exemplo, a consulta retorna os dez principais tipos de espera pelo tempo médio de espera acumulado em um intervalo de 30 minutos. Cumulativo significa que a consulta calcula o tempo total, em milissegundos, gasto aguardando em cada tipo de espera por todas as solicitações em cada segundo. Como várias solicitações podem ser executadas (e esperadas) simultaneamente, o tempo de espera cumulativo em cada segundo pode ser superior a um segundo.
DECLARE @LogicalServerName sysname = 'your-server-name',
@DatabaseName sysname = 'your-database-name',
@ReplicaType sysname = 'Primary',
@DurationMinutes int = 30;
SELECT TOP (10) wait_type,
SUM(CAST((wait_time_ms - prev_wait_time_ms) AS decimal)) * 1000
/
SUM(DATEDIFF(millisecond, prev_sample_time_utc, sample_time_utc))
AS wait_time_ms_per_sec
FROM (
SELECT sample_time_utc,
LAG(sample_time_utc) OVER (PARTITION BY replica_id, wait_type ORDER BY sample_time_utc ASC) AS prev_sample_time_utc,
wait_type,
wait_time_ms,
LAG(wait_time_ms) OVER (PARTITION BY replica_id, wait_type ORDER BY sample_time_utc ASC) AS prev_wait_time_ms
FROM sqldb_database_wait_stats
WHERE sample_time_utc > DATEADD(minute, -@DurationMinutes, SYSUTCDATETIME())
AND
logical_server_name = @LogicalServerName
AND
database_name = @DatabaseName
AND
replica_type = @ReplicaType
) AS w
WHERE sample_time_utc >= prev_sample_time_utc
AND
wait_time_ms >= prev_wait_time_ms
GROUP BY wait_type
ORDER BY wait_time_ms_per_sec DESC;
Conteúdo relacionado
- Monitorar cargas de trabalho de SQL do Azure com o observador de banco de dados (preview)
- Início Rápido: criar um observador de banco de dados para monitorar o SQL do Azure (preview)
- Criar e configurar um observador de banco de dados (preview)
- Perguntas frequentes sobre o observador de banco de dados
- Recursos de aprendizado de Linguagem de Consulta Kusto