Мониторинг производительности База данных SQL Microsoft Azure с помощью динамических административных представлений
Применимо к:База данных SQL Azure
База данных SQL Microsoft Azure позволяет подмножество динамических административных представлений диагностировать проблемы с производительностью, которые могут быть вызваны заблокированными или длительными запросами, узкими местами ресурсов, плохими планами запросов и т. д.
В этой статье содержатся сведения об обнаружении распространенных проблем с производительностью путем запроса динамических административных представлений с помощью T-SQL. Вы можете использовать любой инструмент запроса, например:
Разрешения
В База данных SQL Azure в зависимости от размера вычислительных ресурсов и варианта развертывания запросы к динамическому административному представлению могут потребовать разрешения VIEW DATABASE STATE или VIEW SERVER STATE. Последнее разрешение может быть предоставлено через членство в ##MS_ServerStateReader##
роли сервера.
Чтобы предоставить пользователю конкретного пользователя базы данных разрешение VIEW DATABASE STATE , выполните следующий запрос в качестве примера:
GRANT VIEW DATABASE STATE TO database_user;
Чтобы предоставить членство ##MS_ServerStateReader##
роли сервера для входа для логического сервера в Azure, подключитесь к master
базе данных, а затем выполните следующий запрос в качестве примера:
ALTER SERVER ROLE [##MS_ServerStateReader##] ADD MEMBER [login];
В экземпляре SQL Server и в Управляемом экземпляре SQL Azure динамические административные представления возвращают сведения о состоянии сервера. В Базе данных SQL Azure они возвращают сведения только о текущей логической базе данных.
Выявление проблем производительности ЦП
Если потребление ЦП превышает 80 % в течение длительного периода времени, рассмотрите следующие действия по устранению неполадок, возникающих в настоящее время или произошедших в прошлом.
Проблема с ЦП происходит сейчас
Если проблема происходит прямо сейчас, существует два возможных сценария:
Множество отдельных запросов, которые в совокупности потребляют много ресурсов ЦП
Используйте следующий запрос для идентификации самых ресурсоемких хэшей запросов:
PRINT '-- top 10 Active CPU Consuming Queries (aggregated)--'; SELECT TOP 10 GETDATE() runtime, * FROM (SELECT query_stats.query_hash, SUM(query_stats.cpu_time) 'Total_Request_Cpu_Time_Ms', SUM(logical_reads) 'Total_Request_Logical_Reads', MIN(start_time) 'Earliest_Request_start_Time', COUNT(*) 'Number_Of_Requests', SUBSTRING(REPLACE(REPLACE(MIN(query_stats.statement_text), CHAR(10), ' '), CHAR(13), ' '), 1, 256) AS "Statement_Text" FROM (SELECT req.*, SUBSTRING(ST.text, (req.statement_start_offset / 2)+1, ((CASE statement_end_offset WHEN -1 THEN DATALENGTH(ST.text)ELSE req.statement_end_offset END-req.statement_start_offset)/ 2)+1) AS statement_text FROM sys.dm_exec_requests AS req CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) AS ST ) AS query_stats GROUP BY query_hash) AS t ORDER BY Total_Request_Cpu_Time_Ms DESC;
Длительные запросы, использующие ЦП, все еще выполняются
Используйте следующий запрос для идентификации этих запросов:
PRINT '--top 10 Active CPU Consuming Queries by sessions--'; SELECT TOP 10 req.session_id, req.start_time, cpu_time 'cpu_time_ms', OBJECT_NAME(ST.objectid, ST.dbid) 'ObjectName', SUBSTRING(REPLACE(REPLACE(SUBSTRING(ST.text, (req.statement_start_offset / 2)+1, ((CASE statement_end_offset WHEN -1 THEN DATALENGTH(ST.text)ELSE req.statement_end_offset END-req.statement_start_offset)/ 2)+1), CHAR(10), ' '), CHAR(13), ' '), 1, 512) AS statement_text FROM sys.dm_exec_requests AS req CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) AS ST ORDER BY cpu_time DESC; GO
Проблема с ЦП была в прошлом
Если проблема возникла в прошлом и вы хотите найти первопричину, используйте хранилище запросов. Пользователи с доступом к базе данных могут использовать T-SQL для запроса данных из хранилища запросов. В конфигурации хранилища запросов по умолчанию используется степень детализации 1 час.
Используйте следующий запрос для поиска деятельности ресурсоемких запросов. Этот запрос возвращает 15 самых ресурсоемких запросов. Не забудьте изменить
rsi.start_time >= DATEADD(hour, -2, GETUTCDATE()
:-- Top 15 CPU consuming queries by query hash -- Note that a query hash can have many query ids if not parameterized or not parameterized properly WITH AggregatedCPU AS ( SELECT q.query_hash ,SUM(count_executions * avg_cpu_time / 1000.0) AS total_cpu_ms ,SUM(count_executions * avg_cpu_time / 1000.0) / SUM(count_executions) AS avg_cpu_ms ,MAX(rs.max_cpu_time / 1000.00) AS max_cpu_ms ,MAX(max_logical_io_reads) max_logical_reads ,COUNT(DISTINCT p.plan_id) AS number_of_distinct_plans ,COUNT(DISTINCT p.query_id) AS number_of_distinct_query_ids ,SUM(CASE WHEN rs.execution_type_desc = 'Aborted' THEN count_executions ELSE 0 END) AS Aborted_Execution_Count ,SUM(CASE WHEN rs.execution_type_desc = 'Regular' THEN count_executions ELSE 0 END) AS Regular_Execution_Count ,SUM(CASE WHEN rs.execution_type_desc = 'Exception' THEN count_executions ELSE 0 END) AS Exception_Execution_Count ,SUM(count_executions) AS total_executions ,MIN(qt.query_sql_text) AS sampled_query_text FROM sys.query_store_query_text AS qt INNER JOIN sys.query_store_query AS q ON qt.query_text_id = q.query_text_id INNER JOIN sys.query_store_plan AS p ON q.query_id = p.query_id INNER JOIN sys.query_store_runtime_stats AS rs ON rs.plan_id = p.plan_id INNER JOIN sys.query_store_runtime_stats_interval AS rsi ON rsi.runtime_stats_interval_id = rs.runtime_stats_interval_id WHERE rs.execution_type_desc IN ('Regular','Aborted','Exception') AND rsi.start_time >= DATEADD(HOUR, - 2, GETUTCDATE()) GROUP BY q.query_hash ) ,OrderedCPU AS ( SELECT query_hash ,total_cpu_ms ,avg_cpu_ms ,max_cpu_ms ,max_logical_reads ,number_of_distinct_plans ,number_of_distinct_query_ids ,total_executions ,Aborted_Execution_Count ,Regular_Execution_Count ,Exception_Execution_Count ,sampled_query_text ,ROW_NUMBER() OVER ( ORDER BY total_cpu_ms DESC ,query_hash ASC ) AS query_hash_row_number FROM AggregatedCPU ) SELECT OD.query_hash ,OD.total_cpu_ms ,OD.avg_cpu_ms ,OD.max_cpu_ms ,OD.max_logical_reads ,OD.number_of_distinct_plans ,OD.number_of_distinct_query_ids ,OD.total_executions ,OD.Aborted_Execution_Count ,OD.Regular_Execution_Count ,OD.Exception_Execution_Count ,OD.sampled_query_text ,OD.query_hash_row_number FROM OrderedCPU AS OD WHERE OD.query_hash_row_number <= 15 --get top 15 rows by total_cpu_ms ORDER BY total_cpu_ms DESC;
Когда вы найдете проблемные запросы, настройте их для снижения нагрузки на ЦП. Если у вас нет времени на настройку запросов, вы также можете обновить SLO базы данных, чтобы обойти эту проблему.
Дополнительные сведения об обработке проблем с производительностью ЦП в База данных SQL Azure см. в статье "Диагностика и устранение неполадок с высоким уровнем ЦП в База данных SQL Azure".
Поиск проблем производительности операций ввода-вывода
При выявлении проблем с производительностью ввода-вывода хранилища (ввода-вывода) основные типы ожидания, связанные с проблемами ввода-вывода:
PAGEIOLATCH_*
Проблемы с вводом-выводом файла данных (включая
PAGEIOLATCH_SH
,PAGEIOLATCH_EX
).PAGEIOLATCH_UP
Если имя типа ожидания содержит в нем операции ввода-вывода , она указывает на проблему ввода-вывода. Если в имени ожидания блокировки страницы нет операций ввода-вывода , он указывает на другой тип проблемы (например,tempdb
конфликт).WRITE_LOG
Проблемы с операцией ввода-вывода журнала транзакций.
Если проблема ввода-вывода возникает прямо сейчас
Используйте sys.dm_exec_requests или sys.dm_os_waiting_tasks, чтобы посмотреть wait_type
и wait_time
.
Определение использования данных и операций ввода-вывода журнала
Используйте следующий запрос для идентификации данных и использования операций ввода-вывода журнала. Если объем данных или операций ввода-вывода журнала превышает 80%, это означает, что пользователи использовали доступный ввод-вывод для уровня служб База данных SQL Azure.
SELECT
database_name = DB_NAME()
, UTC_time = end_time
, 'CPU Utilization In % of Limit' = rs.avg_cpu_percent
, 'Data IO In % of Limit' = rs.avg_data_io_percent
, 'Log Write Utilization In % of Limit' = rs.avg_log_write_percent
, 'Memory Usage In % of Limit' = rs.avg_memory_usage_percent
, 'In-Memory OLTP Storage in % of Limit' = rs.xtp_storage_percent
, 'Concurrent Worker Threads in % of Limit' = rs.max_worker_percent
, 'Concurrent Sessions in % of Limit' = rs.max_session_percent
FROM sys.dm_db_resource_stats AS rs --past hour only
ORDER BY rs.end_time DESC;
Дополнительные примеры использования см. в разделе "Мониторинг использованияsys.dm_db_resource_stats
ресурсов" далее в этой статье.
Если достигнуто ограничение ввода-вывода, у вас есть два варианта:
- повышение объема вычислительных ресурсов или уровня служб.
- Определите и настройте запросы, потребляющие большинство операций ввода-вывода.
Просмотр операций ввода-вывода, связанных с буфером, с помощью хранилище запросов
Для варианта 2 можно использовать следующий запрос к хранилище запросов для операций ввода-вывода, связанных с буферами, для просмотра последних двух часов отслеживаемого действия:
-- Top queries that waited on buffer
-- Note these are finished queries
WITH Aggregated AS (SELECT q.query_hash, SUM(total_query_wait_time_ms) total_wait_time_ms, SUM(total_query_wait_time_ms / avg_query_wait_time_ms) AS total_executions, MIN(qt.query_sql_text) AS sampled_query_text, MIN(wait_category_desc) AS wait_category_desc
FROM sys.query_store_query_text AS qt
INNER JOIN sys.query_store_query AS q ON qt.query_text_id=q.query_text_id
INNER JOIN sys.query_store_plan AS p ON q.query_id=p.query_id
INNER JOIN sys.query_store_wait_stats AS waits ON waits.plan_id=p.plan_id
INNER JOIN sys.query_store_runtime_stats_interval AS rsi ON rsi.runtime_stats_interval_id=waits.runtime_stats_interval_id
WHERE wait_category_desc='Buffer IO' AND rsi.start_time>=DATEADD(HOUR, -2, GETUTCDATE())
GROUP BY q.query_hash), Ordered AS (SELECT query_hash, total_executions, total_wait_time_ms, sampled_query_text, wait_category_desc, ROW_NUMBER() OVER (ORDER BY total_wait_time_ms DESC, query_hash ASC) AS query_hash_row_number
FROM Aggregated)
SELECT OD.query_hash, OD.total_executions, OD.total_wait_time_ms, OD.sampled_query_text, OD.wait_category_desc, OD.query_hash_row_number
FROM Ordered AS OD
WHERE OD.query_hash_row_number <= 15 -- get top 15 rows by total_wait_time_ms
ORDER BY total_wait_time_ms DESC;
GO
Просмотр общих операций ввода-вывода журнала для ожиданий WRITELOG
Если тип ожидания имеет значение WRITELOG
, используйте следующий запрос, чтобы просмотреть общий объем операций ввода-вывода журнала по инструкции:
-- Top transaction log consumers
-- Adjust the time window by changing
-- rsi.start_time >= DATEADD(hour, -2, GETUTCDATE())
WITH AggregatedLogUsed
AS (SELECT q.query_hash,
SUM(count_executions * avg_cpu_time / 1000.0) AS total_cpu_ms,
SUM(count_executions * avg_cpu_time / 1000.0) / SUM(count_executions) AS avg_cpu_ms,
SUM(count_executions * avg_log_bytes_used) AS total_log_bytes_used,
MAX(rs.max_cpu_time / 1000.00) AS max_cpu_ms,
MAX(max_logical_io_reads) max_logical_reads,
COUNT(DISTINCT p.plan_id) AS number_of_distinct_plans,
COUNT(DISTINCT p.query_id) AS number_of_distinct_query_ids,
SUM( CASE
WHEN rs.execution_type_desc = 'Aborted' THEN
count_executions
ELSE 0
END
) AS Aborted_Execution_Count,
SUM( CASE
WHEN rs.execution_type_desc = 'Regular' THEN
count_executions
ELSE 0
END
) AS Regular_Execution_Count,
SUM( CASE
WHEN rs.execution_type_desc = 'Exception' THEN
count_executions
ELSE 0
END
) AS Exception_Execution_Count,
SUM(count_executions) AS total_executions,
MIN(qt.query_sql_text) AS sampled_query_text
FROM sys.query_store_query_text AS qt
INNER JOIN sys.query_store_query AS q ON qt.query_text_id = q.query_text_id
INNER JOIN sys.query_store_plan AS p ON q.query_id = p.query_id
INNER JOIN sys.query_store_runtime_stats AS rs ON rs.plan_id = p.plan_id
INNER JOIN sys.query_store_runtime_stats_interval AS rsi ON rsi.runtime_stats_interval_id = rs.runtime_stats_interval_id
WHERE rs.execution_type_desc IN ( 'Regular', 'Aborted', 'Exception' )
AND rsi.start_time >= DATEADD(HOUR, -2, GETUTCDATE())
GROUP BY q.query_hash),
OrderedLogUsed
AS (SELECT query_hash,
total_log_bytes_used,
number_of_distinct_plans,
number_of_distinct_query_ids,
total_executions,
Aborted_Execution_Count,
Regular_Execution_Count,
Exception_Execution_Count,
sampled_query_text,
ROW_NUMBER() OVER (ORDER BY total_log_bytes_used DESC, query_hash ASC) AS query_hash_row_number
FROM AggregatedLogUsed)
SELECT OD.total_log_bytes_used,
OD.number_of_distinct_plans,
OD.number_of_distinct_query_ids,
OD.total_executions,
OD.Aborted_Execution_Count,
OD.Regular_Execution_Count,
OD.Exception_Execution_Count,
OD.sampled_query_text,
OD.query_hash_row_number
FROM OrderedLogUsed AS OD
WHERE OD.query_hash_row_number <= 15 -- get top 15 rows by total_log_bytes_used
ORDER BY total_log_bytes_used DESC;
GO
Определение проблем с производительностью tempdb
При выявлении проблем с производительностью ввода-вывода основные типы ожидания, связанные с tempdb
проблемами PAGELATCH_*
(не PAGEIOLATCH_*
). Однако ожидания PAGELATCH_*
не всегда означают состязание tempdb
. Этот тип ожидания может также указывать на состязание за страницы данных объекта пользователя из-за одновременных запросов к одной странице данных. Чтобы подтвердить спор, используйте sys.dm_exec_requests для подтверждения tempdb
того, что wait_resource
значение начинается с 2:x:y
идентификатора базы данных 2tempdb
, x
является идентификатором файла и y
является идентификатором страницы.
Для tempdb
состязаний распространенный метод заключается в сокращении или перезаписи кода приложения, который используется tempdb
. Распространенные области использования tempdb
:
- Временные таблицы
- Табличные переменные
- Возвращающие табличные значения параметры
- Использование хранилища версий (связанное с длительными транзакциями)
- Запросы с планами запросов, которые используют сортировку, хэш-соединения и буферы
Дополнительные сведения см . в статье tempdb в SQL Azure.
Основные запросы, использующие табличные переменные и временные таблицы
Используйте следующий запрос для идентификации основных запросов, использующих табличные переменные и временные таблицы:
SELECT plan_handle, execution_count, query_plan
INTO #tmpPlan
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_query_plan(plan_handle);
GO
WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS sp)
SELECT plan_handle, stmt.stmt_details.value('@Database', 'varchar(max)') AS 'Database'
, stmt.stmt_details.value('@Schema', 'varchar(max)') AS 'Schema'
, stmt.stmt_details.value('@Table', 'varchar(max)') AS 'table'
INTO #tmp2
FROM
(SELECT CAST(query_plan AS XML) sqlplan, plan_handle FROM #tmpPlan) AS p
CROSS APPLY sqlplan.nodes('//sp:Object') AS stmt(stmt_details);
GO
SELECT t.plan_handle, [Database], [Schema], [table], execution_count
FROM
(SELECT DISTINCT plan_handle, [Database], [Schema], [table]
FROM #tmp2
WHERE [table] LIKE '%@%' OR [table] LIKE '%#%') AS t
INNER JOIN #tmpPlan AS t2 ON t.plan_handle=t2.plan_handle;
GO
DROP TABLE #tmpPlan
DROP TABLE #tmp2
Выявление длительных транзакций
Используйте следующий запрос, чтобы определить длительные транзакции. Длительные транзакции предотвращают очистку постоянного хранилища версий (PVS). Дополнительные сведения см. в статье Устранение неполадок ускоренного восстановления баз данных.
SELECT DB_NAME(dtr.database_id) 'database_name',
sess.session_id,
atr.name AS 'tran_name',
atr.transaction_id,
transaction_type,
transaction_begin_time,
database_transaction_begin_time,
transaction_state,
is_user_transaction,
sess.open_transaction_count,
TRIM(REPLACE(
REPLACE(
SUBSTRING(
SUBSTRING(
txt.text,
(req.statement_start_offset / 2) + 1,
((CASE req.statement_end_offset
WHEN -1 THEN
DATALENGTH(txt.text)
ELSE
req.statement_end_offset
END - req.statement_start_offset
) / 2
) + 1
),
1,
1000
),
CHAR(10),
' '
),
CHAR(13),
' '
)
) Running_stmt_text,
recenttxt.text 'MostRecentSQLText'
FROM sys.dm_tran_active_transactions AS atr
INNER JOIN sys.dm_tran_database_transactions AS dtr
ON dtr.transaction_id = atr.transaction_id
LEFT JOIN sys.dm_tran_session_transactions AS sess
ON sess.transaction_id = atr.transaction_id
LEFT JOIN sys.dm_exec_requests AS req
ON req.session_id = sess.session_id
AND req.transaction_id = sess.transaction_id
LEFT JOIN sys.dm_exec_connections AS conn
ON sess.session_id = conn.session_id
OUTER APPLY sys.dm_exec_sql_text(req.sql_handle) AS txt
OUTER APPLY sys.dm_exec_sql_text(conn.most_recent_sql_handle) AS recenttxt
WHERE atr.transaction_type != 2
AND sess.session_id != @@spid
ORDER BY start_time ASC;
Определение проблем с производительностью ожидания временно предоставляемого буфера памяти
Если основной тип ожидания — RESOURCE_SEMAPHORE
и у вас нет проблем с загрузкой ЦП, у вас проблема с ожиданием временно предоставляемого буфера памяти.
Определение того, является ли ожидание RESOURCE_SEMAPHORE верхней ожиданием
Используйте следующий запрос, чтобы определить, является ли RESOURCE_SEMAPHORE
ожидание верхним ожиданием. Кроме того, это свидетельствует о росте времени ожидания RESOURCE_SEMAPHORE
в последней истории. Дополнительные сведения об устранении неполадок с ожиданием предоставления памяти см. в статье "Устранение проблем с медленной производительностью или низкой памятью, вызванных предоставлением памяти в SQL Server".
SELECT wait_type,
SUM(wait_time) AS total_wait_time_ms
FROM sys.dm_exec_requests AS req
INNER JOIN sys.dm_exec_sessions AS sess
ON req.session_id = sess.session_id
WHERE is_user_process = 1
GROUP BY wait_type
ORDER BY SUM(wait_time) DESC;
Определение операторов, потребляющих большой объем памяти
При возникновении в Базе данных SQL Azure ошибок, связанных с нехваткой памяти, см. сведения в статье о sys.dm_os_out_of_memory_events. Дополнительные сведения см. в статье "Устранение ошибок с памятью с помощью База данных SQL Azure".
Сначала измените следующий скрипт, чтобы обновить соответствующие значения start_time
и end_time
. Затем выполните следующий запрос, чтобы определить операторы с высоким объемом памяти:
SELECT IDENTITY(INT, 1, 1) rowId,
CAST(query_plan AS XML) query_plan,
p.query_id
INTO #tmp
FROM sys.query_store_plan AS p
INNER JOIN sys.query_store_runtime_stats AS r
ON p.plan_id = r.plan_id
INNER JOIN sys.query_store_runtime_stats_interval AS i
ON r.runtime_stats_interval_id = i.runtime_stats_interval_id
WHERE start_time > '2018-10-11 14:00:00.0000000'
AND end_time < '2018-10-17 20:00:00.0000000';
GO
;WITH cte
AS (SELECT query_id,
query_plan,
m.c.value('@SerialDesiredMemory', 'INT') AS SerialDesiredMemory
FROM #tmp AS t
CROSS APPLY t.query_plan.nodes('//*:MemoryGrantInfo[@SerialDesiredMemory[. > 0]]') AS m(c) )
SELECT TOP 50
cte.query_id,
t.query_sql_text,
cte.query_plan,
CAST(SerialDesiredMemory / 1024. AS DECIMAL(10, 2)) SerialDesiredMemory_MB
FROM cte
INNER JOIN sys.query_store_query AS q
ON cte.query_id = q.query_id
INNER JOIN sys.query_store_query_text AS t
ON q.query_text_id = t.query_text_id
ORDER BY SerialDesiredMemory DESC;
Определение десяти основных временно предоставляемых буферов памяти
Используйте следующий запрос для определения десяти основных временно предоставляемых буферов памяти:
SELECT TOP 10
CONVERT(VARCHAR(30), GETDATE(), 121) AS runtime,
r.session_id,
r.blocking_session_id,
r.cpu_time,
r.total_elapsed_time,
r.reads,
r.writes,
r.logical_reads,
r.row_count,
wait_time,
wait_type,
r.command,
OBJECT_NAME(txt.objectid, txt.dbid) 'Object_Name',
TRIM(REPLACE(REPLACE(SUBSTRING(SUBSTRING(TEXT, (r.statement_start_offset / 2) + 1,
( (
CASE r.statement_end_offset
WHEN - 1
THEN DATALENGTH(TEXT)
ELSE r.statement_end_offset
END - r.statement_start_offset
) / 2
) + 1), 1, 1000), CHAR(10), ' '), CHAR(13), ' ')) AS stmt_text,
mg.dop, --Degree of parallelism
mg.request_time, --Date and time when this query requested the memory grant.
mg.grant_time, --NULL means memory has not been granted
mg.requested_memory_kb / 1024.0 requested_memory_mb, --Total requested amount of memory in megabytes
mg.granted_memory_kb / 1024.0 AS granted_memory_mb, --Total amount of memory actually granted in megabytes. NULL if not granted
mg.required_memory_kb / 1024.0 AS required_memory_mb, --Minimum memory required to run this query in megabytes.
max_used_memory_kb / 1024.0 AS max_used_memory_mb,
mg.query_cost, --Estimated query cost.
mg.timeout_sec, --Time-out in seconds before this query gives up the memory grant request.
mg.resource_semaphore_id, --Non-unique ID of the resource semaphore on which this query is waiting.
mg.wait_time_ms, --Wait time in milliseconds. NULL if the memory is already granted.
CASE mg.is_next_candidate --Is this process the next candidate for a memory grant
WHEN 1 THEN
'Yes'
WHEN 0 THEN
'No'
ELSE
'Memory has been granted'
END AS 'Next Candidate for Memory Grant',
qp.query_plan
FROM sys.dm_exec_requests AS r
INNER JOIN sys.dm_exec_query_memory_grants AS mg
ON r.session_id = mg.session_id
AND r.request_id = mg.request_id
CROSS APPLY sys.dm_exec_sql_text(mg.sql_handle) AS txt
CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) AS qp
ORDER BY mg.granted_memory_kb DESC;
Мониторинг подключений
Представление sys.dm_exec_connections можно использовать для получения сведений о подключениях, установленных к определенной базе данных или эластичному пулу, и сведения о каждом подключении. Кроме того, представление sys.dm_exec_sessions позволяет получить сведения обо всех активных подключениях пользователя и внутренних задачах.
Просмотр текущих сеансов
Следующий запрос получает сведения о текущем подключении. Чтобы просмотреть все сеансы, удалите WHERE
предложение.
Все сеансы выполнения в базе данных отображаются только в том случае, если у вас есть разрешение VIEW DATABASE STATE для базы данных при выполнении и sys.dm_exec_sessions
представленийsys.dm_exec_requests
. В противном случае отображается только текущий сеанс.
SELECT
c.session_id, c.net_transport, c.encrypt_option,
c.auth_scheme, s.host_name, s.program_name,
s.client_interface_name, s.login_name, s.nt_domain,
s.nt_user_name, s.original_login_name, c.connect_time,
s.login_time
FROM sys.dm_exec_connections AS c
INNER JOIN sys.dm_exec_sessions AS s
ON c.session_id = s.session_id
WHERE c.session_id = @@SPID; --Remove to view all sessions, if permissions allow
Отслеживание использования ресурсов
Вы можете отслеживать использование ресурсов База данных SQL Azure на уровне запроса с помощью База данных SQL аналитики производительности запросов в портал Azure или хранилище запросов.
Кроме того, для отслеживания использования можно применять следующие представления:
sys.dm_db_resource_stats
Представление sys.dm_db_resource_stats можно использовать в каждой базе данных. В sys.dm_db_resource_stats
представлении показаны последние данные об использовании ресурсов относительно уровня служб. Средний процент нагрузки ЦП, показатели операций ввода-вывода данных, записи в журнал и данные о памяти записываются каждые 15 секунд и хранятся 1 час.
Так как это представление обеспечивает более детализированный взгляд на использование ресурсов, используйте sys.dm_db_resource_stats
сначала для любого анализа текущего состояния или устранения неполадок. Например, этот запрос показывает среднее и максимальное использование ресурсов для текущей базы данных за последний час:
SELECT
Database_Name = DB_NAME(),
tier_limit = COALESCE(rs.dtu_limit, cpu_limit), --DTU or vCore limit
AVG(avg_cpu_percent) AS 'Average CPU use in percent',
MAX(avg_cpu_percent) AS 'Maximum CPU use in percent',
AVG(avg_data_io_percent) AS 'Average data IO in percent',
MAX(avg_data_io_percent) AS 'Maximum data IO in percent',
AVG(avg_log_write_percent) AS 'Average log write use in percent',
MAX(avg_log_write_percent) AS 'Maximum log write use in percent',
AVG(avg_memory_usage_percent) AS 'Average memory use in percent',
MAX(avg_memory_usage_percent) AS 'Maximum memory use in percent'
FROM sys.dm_db_resource_stats AS rs --past hour only
GROUP BY rs.dtu_limit, rs.cpu_limit;
Примеры других запросов см. в sys.dm_db_resource_stats.
sys.resource_stats
Представление sys.resource_stats в master
базе данных содержит дополнительные сведения, которые помогут отслеживать производительность базы данных на определенном уровне служб и размере вычислительных ресурсов. Данные собираются каждые 5 минут и хранятся приблизительно 14 дней. Это представление полезно для анализа использования ресурсов Базы данных за более долгий период.
На следующей диаграмме показано почасовое использование ресурсов процессора для базы данных уровня служб "Премиум" с объемом вычислительных ресурсов P2 в течение недели. Диаграмма начинается в понедельник, охватывает пять рабочих дней и выходные, когда нагрузка заметно ниже.
Судя по этим данным, пиковая нагрузка на процессор составляет чуть более 50 % от максимальной нагрузки для объема вычислительных ресурсов P2 (полдень вторника). Если мощность процессора была главным фактором ресурсного профиля приложения, то вы можете решить, что P2 — оптимальный объем вычислительных ресурсов, который гарантирует стабильную работу с учетом средней нагрузки. Если ожидается рост нагрузки на приложение с течением времени, рекомендуется увеличить запас ресурсов, чтобы приложения не достигло предела производительности. Увеличив объем вычислительных ресурсов, можно избежать заметных пользователю ошибок, которые могут возникнуть из-за нехватки в базе данных мощности для эффективной обработки запросов, особенно в средах, чувствительных к задержкам. Это может быть база данных, поддерживающая приложение, создающее веб-страницы на основе запросов к базе данных.
Для других приложений эту диаграмму можно интерпретировать иначе. Например, если приложение обрабатывало данные по зарплате каждый день и получало ту же диаграмму, то выполнение таких "пакетных заданий" будет эффективным и для объема вычислительных ресурсов P1. Объем вычислительных ресурсов Р1 предоставляет 100 единиц DTU, а P2 — 200 единиц DTU. Таким образом, объем вычислительных ресурсов P1 предоставляет половину объема вычислительных ресурсов P2. Таким образом, 50 процентов использования ЦП на уровне P2 равняется 100 процентам использования ЦП на уровне P1. Если в работе приложения не возникает пауз, возможно, не имеет значения, сколько времени выполняется задание — 2 или 2,5 часа, а важно только, чтобы оно было завершено сегодня. Приложение такой категории может использовать объем вычислительных ресурсов Р1. Вы можете воспользоваться тем, что в определенное время дня использование ресурсов ниже, и перенести пиковую нагрузку именно на этот период. Объем вычислительных ресурсов Р1 может отлично подойти для такого приложения (и сэкономить деньги), если задания будут завершаться вовремя в течение одного дня.
Ядро СУБД предоставляет сведения об используемом ресурсе для каждой активной базы данных в sys.resource_stats
представлении master
базы данных на каждом сервере. Данные в таблице агрегируются каждые 5 минут. На уровнях служб "Базовый", "Стандартный" и "Премиум" может потребоваться более 5 минут, прежде чем данные появятся в таблице, то есть эти данные лучше подходят для ретроспективного анализа, чем для анализа в режиме реального времени. sys.resource_stats
Запросите представление, чтобы просмотреть последнюю историю базы данных и проверить, выбрано ли резервирование, которое вы выбрали для обеспечения производительности при необходимости.
Примечание.
В База данных SQL Azure необходимо подключиться к master
базе данных для запроса sys.resource_stats
в следующих примерах.
В этом примере показано, как отображаются данные в этом представлении.
SELECT TOP 10 *
FROM sys.resource_stats
WHERE database_name = 'userdb1'
ORDER BY start_time DESC;
В следующем примере показаны различные способы использования представления каталога для получения сведений о том sys.resource_stats
, как база данных использует ресурсы:
Чтобы просмотреть использование ресурса прошлой недели для пользовательской базы данных
userdb1
, можно выполнить этот запрос, подставив собственное имя базы данных:SELECT * FROM sys.resource_stats WHERE database_name = 'userdb1' AND start_time > DATEADD(day, -7, GETDATE()) ORDER BY start_time DESC;
Чтобы определить, какой объем вычислительных ресурсов лучше всего подходит для конкретной рабочей нагрузки, нужно детализировать все значения использования ресурсов: ОЗУ, операции чтения и записи, количество рабочих ролей и количество сеансов. Ниже приведен измененный запрос, который используется
sys.resource_stats
для отчета о средних и максимальных значениях этих метрик ресурсов для каждого уровня служб, для которых подготовлена база данных:SELECT rs.database_name , rs.sku , storage_mb = MAX(rs.Storage_in_megabytes) , 'Average CPU Utilization In %' = AVG(rs.avg_cpu_percent) , 'Maximum CPU Utilization In %' = MAX(rs.avg_cpu_percent) , 'Average Data IO In %' = AVG(rs.avg_data_io_percent) , 'Maximum Data IO In %' = MAX(rs.avg_data_io_percent) , 'Average Log Write Utilization In %' = AVG(rs.avg_log_write_percent) , 'Maximum Log Write Utilization In %' = MAX(rs.avg_log_write_percent) , 'Average Requests In %' = AVG(rs.max_worker_percent) , 'Maximum Requests In %' = MAX(rs.max_worker_percent) , 'Average Sessions In %' = AVG(rs.max_session_percent) , 'Maximum Sessions In %' = MAX(rs.max_session_percent) FROM sys.resource_stats AS rs WHERE rs.database_name = 'userdb1' AND rs.start_time > DATEADD(day, -7, GETDATE()) GROUP BY rs.database_name, rs.sku;
С помощью средних и максимальных значений по каждому ресурсу можно оценить, насколько выбранный объем вычислительных ресурсов подходит для вашей рабочей нагрузки. Обычно средние значения из
sys.resource_stats
предоставляют хороший ориентир для определения целевого резервирования. Эти сведения следует использовать в качестве отправной точки анализа.Для баз данных модели приобретения DTU:
Например, вы можете использовать уровень служб "Стандартный" с объемом вычислительных ресурсов S2. При этом средняя нагрузка на процессор и число операций чтения и записи ввода-вывода составляют меньше 40 %, среднее число рабочих ролей — меньше 50, а среднее количество сеансов — меньше 200. Для такой рабочей нагрузки может подойти объем вычислительных ресурсов S1. Вы легко можете определить, отвечает ли уровень базы данных ограничениям рабочих ролей и сеансов. Чтобы узнать, соответствует ли база данных более низкому размеру вычислений, разделите число DTU меньшего размера вычислений на число DTU текущего размера вычислений, а затем умножьте результат на 100:
S1 DTU / S2 DTU * 100 = 20 / 50 * 100 = 40
Результатом будет относительная разница производительности между двумя объемами вычислительных ресурсов в процентах. Если использование ресурсов не превышает это значение, для рабочей нагрузки может подойти более низкий объем вычислительных ресурсов. Однако необходимо рассмотреть все диапазоны значений использования ресурсов, а также определить (в процентном отношении), как часто рабочая нагрузка базы банных будет вписываться в рамки более низкого объема вычислительных ресурсов. Следующий запрос отображает процентный показатель измерения ресурсов, исходя из 40-процентного порога, вычисленного в предыдущем примере.
SELECT database_name, 100*((COUNT(database_name) - SUM(CASE WHEN avg_cpu_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'CPU Fit Percent', 100*((COUNT(database_name) - SUM(CASE WHEN avg_log_write_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'Log Write Fit Percent', 100*((COUNT(database_name) - SUM(CASE WHEN avg_data_io_percent >= 40 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'Physical Data IO Fit Percent' FROM sys.resource_stats WHERE start_time > DATEADD(day, -7, GETDATE()) AND database_name = 'sample' --remove to see all databases GROUP BY database_name;
В зависимости от уровня служб базы данных вы можете определить, подходит ли более низкий объем вычислительных ресурсов для вашей рабочей нагрузки. Если целевой показатель рабочей нагрузки составляет 99,9 % и указанный выше запрос возвращает значение больше 99,9 % для всех трех измерений ресурсов, весьма вероятно, что рабочую нагрузку можно выполнять с более низким объемов вычислительных ресурсов.
Процентное значение также поможет вам понять, следует ли перейти на следующий объем вычислительных ресурсов для выполнения требований. Например, использование ЦП для образца базы данных за прошлую неделю:
Средняя нагрузка ЦП, % Максимальная нагрузка ЦП, % 24,5 100.00 Средняя нагрузка ЦП равна приблизительно одной четвертой ограничения объема вычислительных ресурсов, что вполне соответствует объему вычислительных ресурсов базы данных.
Для модели приобретения DTU и баз данных моделей приобретения виртуальных ядер:
Максимальное значение показывает, что база данных достигает предела размера вычислительных ресурсов. Требуется ли перейти на более высокий объем вычислительных ресурсов? Определите, сколько раз рабочая нагрузка достигает 100 %, и сравните это значение с целевым показателем рабочей нагрузки базы данных.
SELECT database_name, 100*((COUNT(database_name) - SUM(CASE WHEN avg_cpu_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'CPU Fit Percent', 100*((COUNT(database_name) - SUM(CASE WHEN avg_log_write_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'Log Write Fit Percent', 100*((COUNT(database_name) - SUM(CASE WHEN avg_data_io_percent >= 100 THEN 1 ELSE 0 END) * 1.0) / COUNT(database_name)) AS 'Physical Data IO Fit Percent' FROM sys.resource_stats WHERE start_time > DATEADD(day, -7, GETDATE()) AND database_name = 'sample' --remove to see all databases GROUP BY database_name;
Эти проценты — это количество примеров рабочей нагрузки, подходящих для текущего размера вычислительных ресурсов. Если этот запрос возвращает значение менее 99,9 процента для любого из трех измерений ресурсов, выборка средней рабочей нагрузки превысила ограничения. Рассмотрите возможность перехода к следующему более высокому размеру вычислительных ресурсов или используйте методы настройки приложений, чтобы уменьшить нагрузку на базу данных.
Примечание.
Для эластичных пулов можно отслеживать отдельные базы данных в пуле с помощью способов, описанных в этом разделе. Вы также можете отслеживать пул в целом. Дополнительные сведения см. в статье Мониторинг пула эластичных баз данных и управление им на портале Azure.
Максимальное количество параллельных запросов
Чтобы просмотреть текущее количество одновременных запросов, выполните этот запрос в пользовательской базе данных:
SELECT COUNT(*) AS [Concurrent_Requests]
FROM sys.dm_exec_requests AS R;
Чтобы проанализировать рабочую нагрузку базы данных, измените этот запрос, чтобы отфильтровать определенную базу данных, которую необходимо проанализировать. Сначала обновите имя базы данных из MyDatabase
требуемой базы данных, а затем выполните следующий запрос, чтобы найти количество одновременных запросов в этой базе данных:
SELECT COUNT(*) AS [Concurrent_Requests]
FROM sys.dm_exec_requests AS R
INNER JOIN sys.databases AS D
ON D.database_id = R.database_id
AND D.name = 'MyDatabase';
Это только моментальный снимок в один момент времени. Для лучшего понимания рабочей нагрузки и требований к параллельным запросам потребуется собрать большое количество примеров с течением времени.
Максимальное число параллельных событий входа
Вы можете проанализировать шаблоны пользователей и приложений, чтобы получить представление о частоте событий входа. Кроме того, можно запустить реальные нагрузки в тестовой среде, чтобы убедиться в том, что вы не приближаетесь к этим или другим ограничениям, описанным в этой статье. Не существует единого запроса или динамического административного представления, с помощью которых можно просмотреть количество параллельных операций входа или журнал.
Если несколько клиентов используют ту же строку подключения, служба проверяет подлинность каждого входа. Если 10 пользователей одновременно подключаются к базе данных с использованием того же имени пользователя и пароля, это будет 10 параллельных операций входа. Это ограничение применяется только на время входа и проверки подлинности. Если те же 10 пользователей последовательно подключатся к базе данных, количество параллельных операций входа никогда не будет больше 1.
Примечание.
Сейчас это ограничение не применимо к базам данных в пулах эластичных баз данных.
Максимальное число сеансов
Чтобы просмотреть количество текущих активных сеансов, выполните этот запрос в базе данных:
SELECT COUNT(*) AS [Sessions]
FROM sys.dm_exec_connections;
При анализе рабочей нагрузки SQL Server измените запрос, чтобы сосредоточиться на определенной базе данных. Этот запрос помогает определить возможные потребности сеанса для базы данных, если вы планируете переместить ее в Azure. Сначала обновите имя базы данных из MyDatabase
требуемой базы данных, а затем выполните следующий запрос:
SELECT COUNT(*) AS [Sessions]
FROM sys.dm_exec_connections AS C
INNER JOIN sys.dm_exec_sessions AS S
ON (S.session_id = C.session_id)
INNER JOIN sys.databases AS D
ON (D.database_id = S.database_id)
WHERE D.name = 'MyDatabase';
Опять же, эти запросы возвращают значение счетчика на определенный момент времени. Сбор нескольких образцов за определенный период времени обеспечивает лучшее понимание использования сеансов.
Вы можете получить историческую статистику по сеансам, запросить представление каталога sys.resource_stats и просмотреть active_session_count
столбец.
Вычисление размеров базы данных и объектов
Следующий запрос возвращает размер базы данных в мегабайтах:
-- Calculates the size of the database.
SELECT SUM(CAST(FILEPROPERTY(name, 'SpaceUsed') AS bigint) * 8192.) / 1024 / 1024 AS size_mb
FROM sys.database_files
WHERE type_desc = 'ROWS';
Следующий запрос возвращает размер отдельных объектов базы данных в мегабайтах:
-- Calculates the size of individual database objects.
SELECT o.name, SUM(ps.reserved_page_count) * 8.0 / 1024 AS size_mb
FROM sys.dm_db_partition_stats AS ps
INNER JOIN sys.objects AS o
ON ps.object_id = o.object_id
GROUP BY o.name
ORDER BY size_mb DESC;
Мониторинг производительности запросов
Медленные или длительные запросы могут потреблять значительные системные ресурсы. В этом разделе показано, как использовать динамические административные представления для обнаружения нескольких распространенных проблем с производительностью запросов с помощью динамического представления управления sys.dm_exec_query_stats . Представление содержит по одной строке для каждой инструкции запроса в плане в кэше, а время жизни строк связано с самим планом. Когда план удаляется из кэша, соответствующие строки исключаются из представления.
Поиск основных запросов по времени ЦП
В следующем примере возвращаются сведения о 15 лучших запросах, ранжированных по среднему времени ЦП на выполнение. В этом примере выполняется сбор запросов по хэшу запроса, то есть логически схожие запросы группируются по общему потреблению ресурсов.
SELECT TOP 15 query_stats.query_hash AS "Query Hash",
SUM(query_stats.total_worker_time) / SUM(query_stats.execution_count) AS "Avg CPU Time",
MIN(query_stats.statement_text) AS "Statement Text"
FROM
(SELECT QS.*,
SUBSTRING(ST.text, (QS.statement_start_offset/2) + 1,
((CASE statement_end_offset
WHEN -1 THEN DATALENGTH(ST.text)
ELSE QS.statement_end_offset END
- QS.statement_start_offset)/2) + 1) AS statement_text
FROM sys.dm_exec_query_stats AS QS
CROSS APPLY sys.dm_exec_sql_text(QS.sql_handle) AS ST
) AS query_stats
GROUP BY query_stats.query_hash
ORDER BY 2 DESC;
Мониторинг планов запросов для накопительного времени ЦП
Неэффективный план запросов может повысить потребление ресурсов ЦП. В следующем примере определяется, какой запрос использует самый накопительный ЦП в последней истории.
SELECT
highest_cpu_queries.plan_handle,
highest_cpu_queries.total_worker_time,
q.dbid,
q.objectid,
q.number,
q.encrypted,
q.[text]
FROM
(SELECT TOP 15
qs.plan_handle,
qs.total_worker_time
FROM
sys.dm_exec_query_stats AS qs
ORDER BY qs.total_worker_time desc
) AS highest_cpu_queries
CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS q
ORDER BY highest_cpu_queries.total_worker_time DESC;
Мониторинг заблокированных запросов
Медленные или длительные запросы могут вызывать избыточное потребление ресурсов, что приводит к блокировке запросов. Причиной блокировки может быть неэффективная структура приложений, неудачные планы запросов, отсутствие полезных индексов и т. д.
Представление можно использовать sys.dm_tran_locks
для получения сведений о текущем действии блокировки в базе данных. Пример кода см . в sys.dm_tran_locks. Дополнительные сведения об устранении неполадок с блокировкой см. в статье Изучение и устранение проблем с блокировкой SQL Azure.
Мониторинг взаимоблокировок
В некоторых случаях два или более запросов могут взаимно блокировать друг друга, что приводит к взаимоблокировке.
Вы можете создать трассировку расширенных событий в базе данных SQL Azure для записи событий взаимоблокировки, а затем найти связанные запросы и планы их выполнения в хранилище запросов. Дополнительные сведения см. в разделе "Анализ и предотвращение взаимоблокировок" в База данных SQL Azure, включая лабораторию, чтобы вызвать взаимоблокировку в AdventureWorksLT. Узнайте больше о типах ресурсов, которые могут взаимоблокировки.
Связанный контент
- Введение в Базу данных SQL Azure и Управляемый экземпляр SQL Azure
- Диагностика и устранение неполадок с высокой загрузкой ЦП в Базе данных SQL Azure
- Настройка приложений и баз данных для повышения производительности в Базе данных SQL Azure
- Изучение и устранение проблем с блокировкой Базы данных SQL Azure
- Анализ и предотвращение взаимоблокировок в Базе данных SQL Azure
- Мониторинг рабочих нагрузок SQL Azure с помощью наблюдателя за базами данных (предварительная версия)
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по