Мониторинг производительности Microsoft Управляемый экземпляр SQL Azure с помощью динамических административных представлений
Область применения: Управляемый экземпляр SQL Azure
Microsoft Управляемый экземпляр SQL Azure позволяет подмножество динамических административных представлений (DMV) диагностировать проблемы с производительностью, которые могут быть вызваны заблокированными или длительными запросами, узкими местами ресурсов, плохими планами запросов и т. д. Эта статья содержит информацию о том, как выявлять распространенные проблемы производительности с помощью динамических административных представлений.
В этой статье описывается Управляемый экземпляр SQL Azure, см. также сведения о мониторинге производительности База данных SQL Microsoft Azure с помощью динамических административных представлений.
Разрешения
В Управляемом экземпляре SQL Azure для запроса динамического административного представления требуется наличие разрешений VIEW SERVER STATE.
GRANT VIEW SERVER STATE TO database_user;
В экземпляре SQL Server и в Управляемом экземпляре 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 id if not parameterized or not parameterized properly
-- it grabs a sample query text by min
WITH AggregatedCPU AS (SELECT q.query_hash, SUM(count_executions * avg_cpu_time / 1000.0) AS total_cpu_millisec, SUM(count_executions * avg_cpu_time / 1000.0)/ SUM(count_executions) AS avg_cpu_millisec, MAX(rs.max_cpu_time / 1000.00) AS max_cpu_millisec, 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
JOIN sys.query_store_query AS q ON qt.query_text_id=q.query_text_id
JOIN sys.query_store_plan AS p ON q.query_id=p.query_id
JOIN sys.query_store_runtime_stats AS rs ON rs.plan_id=p.plan_id
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_millisec, avg_cpu_millisec, max_cpu_millisec, 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_millisec DESC, query_hash ASC) AS RN
FROM AggregatedCPU)
SELECT OD.query_hash, OD.total_cpu_millisec, OD.avg_cpu_millisec, OD.max_cpu_millisec, 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.RN
FROM OrderedCPU AS OD
WHERE OD.RN<=15
ORDER BY total_cpu_millisec DESC;
Когда вы найдете проблемные запросы, настройте их для снижения нагрузки на ЦП. Если у вас нет времени на настройку запросов, можно также обновить SLO управляемого экземпляра, чтобы обойти эту проблему.
Поиск проблем производительности операций ввода-вывода
При определении проблем с производительностью операций ввода-вывода учтите главные типы ожидания, связанные с проблемами ввода-вывода:
PAGEIOLATCH_*
Для ошибок ввода-вывода в файлах данных (включая
PAGEIOLATCH_SH
,PAGEIOLATCH_EX
,PAGEIOLATCH_UP
). Если имя типа ожидания содержит IO, это указывает на проблему ввода-вывода. Если в имени ожидания блокировки страницы нет операций ввода-вывода , он указывает на другой тип проблемы (например,tempdb
конфликт).WRITE_LOG
Для проблем ввода-вывода в журнале транзакций.
Если проблема ввода-вывода происходит прямо сейчас
Используйте sys.dm_exec_requests или sys.dm_os_waiting_tasks, чтобы посмотреть wait_type
и wait_time
.
Просмотр операций ввода-вывода, связанных с буфером, с помощью хранилища запросов
Во втором варианте используйте следующий запрос к хранилищу запросов об операциях ввода-вывода, связанных с буфером, для просмотра действий за последние два часа:
-- 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
JOIN sys.query_store_query AS q ON qt.query_text_id=q.query_text_id
JOIN sys.query_store_plan AS p ON q.query_id=p.query_id
JOIN sys.query_store_wait_stats AS waits ON waits.plan_id=p.plan_id
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 RN
FROM Aggregated)
SELECT OD.query_hash, OD.total_executions, OD.total_wait_time_ms, OD.sampled_query_text, OD.wait_category_desc, OD.RN
FROM Ordered AS OD
WHERE OD.RN<=15
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_millisec,
SUM(count_executions * avg_cpu_time / 1000.0) / SUM(count_executions) AS avg_cpu_millisec,
SUM(count_executions * avg_log_bytes_used) AS total_log_bytes_used,
MAX(rs.max_cpu_time / 1000.00) AS max_cpu_millisec,
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
JOIN sys.query_store_query AS q
ON qt.query_text_id = q.query_text_id
JOIN sys.query_store_plan AS p
ON q.query_id = p.query_id
JOIN sys.query_store_runtime_stats AS rs
ON rs.plan_id = p.plan_id
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 RN
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.RN
FROM OrderedLogUsed AS OD
WHERE OD.RN <= 15
ORDER BY total_log_bytes_used DESC;
GO
Поиск проблем производительности tempdb
При определении проблем с производительностью операций ввода-вывода главные типы ожидания, связанные с проблемами tempdb
, — PAGELATCH_*
(не PAGEIOLATCH_*
). Однако ожидания PAGELATCH_*
не всегда означают состязание tempdb
. Этот тип ожидания может также указывать на состязание за страницы данных объекта пользователя из-за одновременных запросов к одной странице данных. Чтобы получить дополнительные доказательства состязания tempdb
, используйте sys.dm_exec_requests для подтверждения того, что значение wait_resource начинается с 2:x:y
, где 2 — tempdb
, идентификатор базы данных, x
— идентификатор файла, а y
— идентификатор страницы.
Для tempdb
состязаний распространенный метод заключается в сокращении или перезаписи кода приложения, который используется tempdb
. Распространенные области использования tempdb
:
- Временные таблицы
- Табличные переменные
- Возвращающие табличные значения параметры
- Использование хранилища версий (связанное с длительными транзакциями)
- Запросы с планами запросов, которые используют сортировку, хэш-соединения и буферы
Основные запросы, использующие табличные переменные и временные таблицы
Используйте следующий запрос для идентификации основных запросов, использующих табличные переменные и временные таблицы:
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)') 'Database', stmt.stmt_details.value('@Schema', 'varchar(max)') 'Schema', stmt.stmt_details.value('@Table', 'varchar(max)') '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
JOIN #tmpPlan AS t2 ON t.plan_handle=t2.plan_handle;
Выявление длительных транзакций
Используйте следующий запрос, чтобы определить длительные транзакции. Длительные транзакции мешают очистке хранилища версий.
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_SEMAHPORE
и у вас нет проблем с загрузкой ЦП, у вас проблема с ожиданием временно предоставляемого буфера памяти.
Определение типа ожидания RESOURCE_SEMAHPORE
в качестве основного
Используйте следующий запрос для определения того, что тип ожидания RESOURCE_SEMAHPORE
является основным
SELECT wait_type,
SUM(wait_time) AS total_wait_time_ms
FROM sys.dm_exec_requests AS req
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;
Определение операторов, потребляющих большой объем памяти
При возникновении ошибок, связанных с нехваткой памяти, см. сведения в статье о sys.dm_os_out_of_memory_events.
Используйте следующий запрос для определения операторов, потребляющих большой объем памяти:
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
JOIN sys.query_store_runtime_stats AS r
ON p.plan_id = r.plan_id
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
JOIN sys.query_store_query AS q
ON cte.query_id = q.query_id
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),
' '
)
) 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
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;
Вычисление размера базы данных и объектов
Следующий запрос возвращает размер базы данных в мегабайтах:
-- Calculates the size of the database.
SELECT SUM(CAST(FILEPROPERTY(name, 'SpaceUsed') AS bigint) * 8192.) / 1024 / 1024 AS DatabaseSizeInMB
FROM sys.database_files
WHERE type_desc = 'ROWS';
GO
Следующий запрос возвращает размер отдельных объектов базы данных в мегабайтах:
-- Calculates the size of individual database objects.
SELECT sys.objects.name, SUM(reserved_page_count) * 8.0 / 1024
FROM sys.dm_db_partition_stats, sys.objects
WHERE sys.dm_db_partition_stats.object_id = sys.objects.object_id
GROUP BY sys.objects.name;
GO
Мониторинг подключений
Представление sys.dm_exec_connections можно использовать для получения сведений о подключениях, установленных к конкретному управляемому экземпляру, и сведения о каждом подключении. Кроме того, представление sys.dm_exec_sessions позволяет получить сведения обо всех активных подключениях пользователя и внутренних задачах.
Следующий запрос получает информацию о текущем подключении:
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
JOIN sys.dm_exec_sessions AS s
ON c.session_id = s.session_id
WHERE c.session_id = @@SPID;
Отслеживание использования ресурсов
Вы можете отслеживать использование ресурсов с помощью хранилище запросов так же, как и в SQL Server.
Вы также можете отслеживать использование с помощью sys.dm_db_resource_stats и sys.server_resource_stats.
sys.dm_db_resource_stats
Представление sys.dm_db_resource_stats можно использовать в каждой базе данных. В sys.dm_db_resource_stats
представлении показаны последние данные об использовании ресурсов относительно уровня служб. Средний процент нагрузки ЦП, показатели операций ввода-вывода данных, записи в журнал и данные о памяти записываются каждые 15 секунд и хранятся 1 час.
Так как это представление обеспечивает более детализированный взгляд на использование ресурсов, используйте sys.dm_db_resource_stats
сначала для любого анализа текущего состояния или устранения неполадок. Например, этот запрос показывает среднее и максимальное использование ресурсов для текущей базы данных за последний час:
SELECT
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;
Примеры других запросов см. в sys.dm_db_resource_stats.
sys.server_resource_stats
Вы можете использовать sys.server_resource_stats для возврата сведений об использовании ЦП, операциях ввода-вывода и хранении данных для Управляемого экземпляра SQL Azure. Эти данные собираются и объединяются с пятиминутными интервалами. Для каждых 15 секунд отчета выделяется одна строка. Возвращаемые данные включают загрузку ЦП, размер хранилища, использование операций ввода-вывода и SKU управляемого экземпляра. Данные предыстории хранятся приблизительно в течение 14 суток.
В примерах показаны различные способы использования sys.server_resource_stats
представления каталога для получения сведений о том, как экземпляр использует ресурсы.
Следующий пример возвращает среднее использование ЦП за последние семь дней:
DECLARE @s datetime; DECLARE @e datetime; SET @s= DateAdd(d,-7,GetUTCDate()); SET @e= GETUTCDATE(); SELECT AVG(avg_cpu_percent) AS Average_Compute_Utilization FROM sys.server_resource_stats WHERE start_time BETWEEN @s AND @e; GO
В следующем примере возвращается среднее пространство хранилища, используемое экземпляром в день, чтобы разрешить анализ тенденций роста:
DECLARE @s datetime; DECLARE @e datetime; SET @s= DateAdd(d,-7,GetUTCDate()); SET @e= GETUTCDATE(); SELECT Day = convert(date, start_time), AVG(storage_space_used_mb) AS Average_Space_Used_mb FROM sys.server_resource_stats WHERE start_time BETWEEN @s AND @e GROUP BY convert(date, start_time) ORDER BY convert(date, start_time); GO
Максимальное количество параллельных запросов
Чтобы просмотреть текущее количество одновременных запросов, выполните этот запрос Transact-SQL в базе данных:
SELECT COUNT(*) AS [Concurrent_Requests]
FROM sys.dm_exec_requests R;
Чтобы проанализировать рабочую нагрузку отдельной базы данных, измените этот запрос, чтобы отфильтровать определенную базу данных, которую необходимо проанализировать. Например, если у вас есть база данных с именем MyDatabase
, этот запрос Transact-SQL возвращает количество одновременных запросов в этой базе данных:
SELECT COUNT(*) AS [Concurrent_Requests]
FROM sys.dm_exec_requests R
INNER JOIN sys.databases D ON D.database_id = R.database_id
AND D.name = 'MyDatabase';
Это только моментальный снимок в один момент времени. Для лучшего понимания рабочей нагрузки и требований к параллельным запросам потребуется собрать большое количество примеров с течением времени.
Максимальное число параллельных операций входа
Чтобы получить представление о частоте входа, можно проанализировать шаблоны работы пользователей и приложений. Кроме того, можно запустить реальные нагрузки в тестовой среде, чтобы убедиться в том, что вы не приближаетесь к этим или другим ограничениям, описанным в этой статье. Не существует единого запроса или динамического административного представления, с помощью которых можно просмотреть количество параллельных операций входа или журнал.
Если несколько клиентов используют ту же строку подключения, служба проверяет подлинность каждого входа. Если 10 пользователей одновременно подключаются к базе данных с использованием того же имени пользователя и пароля, это будет 10 параллельных операций входа. Это ограничение применяется только на время входа и проверки подлинности. Если те же 10 пользователей последовательно подключатся к базе данных, количество параллельных операций входа никогда не будет больше 1.
Максимальное число сеансов
Чтобы просмотреть число текущих активных сеансов, выполните в базе данных этот запрос Transact-SQL:
SELECT COUNT(*) AS [Sessions]
FROM sys.dm_exec_connections;
При анализе рабочей нагрузки SQL Server измените запрос, чтобы сосредоточиться на определенной базе данных. Это поможет определить возможные потребности в сеансах для этой базы данных, если вы собираетесь переместить ее в Azure.
SELECT COUNT(*) AS [Sessions]
FROM sys.dm_exec_connections C
INNER JOIN sys.dm_exec_sessions S ON (S.session_id = C.session_id)
INNER JOIN sys.databases D ON (D.database_id = S.database_id)
WHERE D.name = 'MyDatabase';
Опять же, эти запросы возвращают значение счетчика на определенный момент времени. Сбор нескольких образцов за определенный период времени обеспечивает лучшее понимание использования сеансов.
Мониторинг производительности запросов
Медленные или длительные запросы могут потреблять значительные системные ресурсы. В этом разделе показано, как использовать динамические представления управления для выявления нескольких распространенных проблем производительности запросов.
Поиск верхних N запросов
В следующем примере возвращаются сведения о пяти первых запросах, отсортированных по среднему времени ЦП. В этом примере выполняется сбор запросов по хэшу запроса, то есть логически схожие запросы группируются по общему потреблению ресурсов.
SELECT TOP 5 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;
Мониторинг заблокированных запросов
Медленные или длительные запросы могут вызывать избыточное потребление ресурсов, что приводит к блокировке запросов. Причиной блокировки может быть неэффективная структура приложений, неудачные планы запросов, отсутствие полезных индексов и т. д. Представление sys.dm_tran_locks можно использовать для получения сведений о текущих блокировках в базе данных. Пример кода см . в sys.dm_tran_locks. Дополнительные сведения об устранении неполадок с блокировкой см. в статье Изучение и устранение проблем с блокировкой SQL Azure.
Мониторинг взаимоблокировок
В некоторых случаях два или более запросов могут взаимно блокировать друг друга, что приводит к взаимоблокировке.
Вы можете создать трассировку расширенных событий для записи событий взаимоблокировки, а затем найти связанные запросы и планы их выполнения в хранилище запросов.
Сведения о Управляемый экземпляр SQL Azure см. в руководстве по взаимоблокировкам.
Мониторинг планов запросов
Неэффективный план запросов может повысить потребление ресурсов ЦП. В следующем примере представление sys.dm_exec_query_stats используется, чтобы определить, какой запрос использует наибольшее количество ресурсов ЦП.
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 50
qs.plan_handle,
qs.total_worker_time
FROM
sys.dm_exec_query_stats 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;
Другие параметры мониторинга
Мониторинг с помощью наблюдателя за базой данных (предварительная версия)
Наблюдатель за базами данных собирает подробные данные мониторинга рабочей нагрузки, чтобы получить подробное представление о производительности, конфигурации и работоспособности базы данных. Панели мониторинга в портал Azure предоставляют одноуровневое представление вашего объекта SQL Azure и подробное представление каждого отслеживаемого ресурса. Данные собираются в централизованное хранилище данных в подписке Azure. Вы можете запрашивать, анализировать, экспортировать, визуализировать собранные данные и интегрировать их с подчиненными системами.
Дополнительные сведения о наблюдателе за базами данных см. в следующих статьях:
- Мониторинг рабочих нагрузок SQL Azure с помощью наблюдателя за базами данных (предварительная версия)
- Краткое руководство. Создание наблюдателя за базами данных для мониторинга SQL Azure (предварительная версия)
- Создание и настройка наблюдателя за базой данных (предварительная версия)
- Сбор и наборы данных наблюдателя за базами данных (предварительная версия)
- Анализ данных мониторинга наблюдателя за базами данных (предварительная версия)
- Вопросы и ответы наблюдателя за базами данных
Мониторинг с помощью Azure Monitor
Azure Monitor предоставляет различные группы сбора диагностических данных, метрики и конечные точки для мониторинга Управляемый экземпляр SQL Azure. Дополнительные сведения см. в статье "Мониторинг Управляемый экземпляр SQL Azure с помощью Azure Monitor". Аналитика SQL Azure (предварительная версия) предоставляет средства интеграции с платформой Azure Monitor, на которой многие решения мониторинга уже вышли из стадии активной разработки. Дополнительные параметры мониторинга см. в разделе "Мониторинг и настройка производительности" в Управляемый экземпляр SQL Azure и База данных SQL Azure.
См. также
- Динамические административные представления и функции (Transact-SQL)
- Системные динамические административные представления
Следующие шаги
- Введение в Базу данных SQL Azure и Управляемый экземпляр SQL Azure
- Настройка приложений и баз данных для повышения производительности в Управляемый экземпляр SQL Azure
- Общие сведения о проблемах, связанных с блокировкой SQL Server, и их устранении
- Анализ и предотвращение взаимоблокировок в Управляемый экземпляр SQL Azure
- sys.server_resource_stats (Управляемый экземпляр SQL Azure)