Спасибо. Погонял на тестовом сервере с несколькими базами - некоторые запросы выдали любопытные вещи. На которые раньше не обратил бы внимания и жил бы себе спокойно... :)
(4) если так рассуждать, то по анализу производительности в инете тоже статей куча. Хотелось бы здесь сразу видеть ссылки на эти статьи, которые помогут расшифровать результаты.
(6) Armando, тут должна быть ссылка на книгу "Настольная книга эксперта по технологическим вопросам"... Серьезно, тут не пара статей будет. Даже не пара десятков.... Я бы так и гуглил: "производительность 1С план запроса", "производительность 1С индексы", "производительность 1С блокировки... я так и гуглил в свое время, почитал и пошел книжки читать, чтобы информация не кусками надерганная была, а упорядоченная...
Хороший наборчик.
Вот если бы еще все это с анализом на стороне 1С. Т.е. чтоб и поля показал, из которых индексы состоят и т.п. Например как у Алексея: http://infostart.ru/public/81694/
(14) индексы можно посмотреть отчетом структура бд или любой другой аналогичной, при помощи нее можно найти и избыточные индексы и убрать галочку индексировать с соответствующих реквизитов
(20) да, согласен, я говорил о простых и явно избыточных по определенному реквизиту, к тому же к сожалению платформа 1С не позволяет создавать рекомендуемые индексы
я говорил о простых и явно избыточных по определенному реквизиту
Ну в плане новых типовых это уже не так критично, года с 2008 в 1С всё-таки одумались и перестали в типовых конфигурациях выставлять режим индексирования в реквизитах, оставив специалистам на месте решать какие поля требуют дополнительного индексирования.
(23) однако, это не мешает некоторым "специалистам" индексировать эти реквизиты, о чем я и толкую. Не у всех конфиурации под контролем своих программистов, а достаются в наследство от "топовых" франчей. Еще раз подчеркиваю, что подход должен быть сугубо индивидуальный и я осознанно не привожу конкретики типа делай раз, делай два и ... опа ускорение 1с в 100 раз
(23) h00k,
Ага. См. регистры аналитики учета затрат в УПП )
Ну есть все же поля, однозначно требующие индексирования - и будь конфа тридцать три раза типовой - индекс там стоять должен )
Временами, при восстановлении базы из архива может сбиться настройка смещения дат, что чревато серьезными проблемами.
Проверить настройку смещения дат можно следующим скриптом:
SELECT TOP 1 Offset FROM _YearOffset
Для оценки самых тяжелых запросов я использую немного другие скрипты:
1. Топ 10 самых тяжелых для процессора
SELECT TOP 10
[Average CPU used] = total_worker_time / qs.execution_count
,[Total CPU used] = total_worker_time
,[Execution count] = qs.execution_count
,[Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2,
(CASE WHEN qs.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE qs.statement_end_offset END -
qs.statement_start_offset)/2)
,[Parent Query] = qt.text
,DatabaseName = DB_NAME(qt.dbid)
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
ORDER BY [Average CPU used] DESC;
Показать
2. Топ 10 самых тяжелых по вводу/выводу
SELECT TOP 10
[Average IO] = (total_logical_reads + total_logical_writes) / qs.execution_count
,[Total IO] = (total_logical_reads + total_logical_writes)
,[Execution count] = qs.execution_count
,[Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2,
(CASE WHEN qs.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE qs.statement_end_offset END - qs.statement_start_offset)/2)
,[Parent Query] = qt.text
,DatabaseName = DB_NAME(qt.dbid)
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
ORDER BY [Average IO] DESC;
Показать
Статистика ввода/вывода по файлам баз данных
USE master
GO
SELECT TOP 10 DB_NAME(saf.dbid) AS [База данных]
, saf.name AS [Логическое имя]
, vfs.BytesRead/1048576 AS [Прочитано (Мб)]
, vfs.BytesWritten/1048576 AS [Записано (Мб)]
, saf.filename AS [Путь к файлу]
FROM sysaltfiles AS saf
JOIN :: fn_virtualfilestats(NULL,NULL) AS vfs
ON vfs.dbid = saf.dbid
AND vfs.fileid = saf.fileid
AND saf.dbid NOT IN (1,3,4)
ORDER BY vfs.BytesRead/1048576 + BytesWritten/1048576 DESC
GO
Показать
Статистика ввода/вывода по дискам
SELECT SUBSTRING(saf.physical_name, 1, 1) AS [Диск]
, SUM(vfs.num_of_bytes_read/1048576) AS [Прочитано (Мб)]
, SUM(vfs.num_of_bytes_written/1048576) AS [Записано (Мб)]
FROM sys.master_files AS saf
JOIN sys.dm_io_virtual_file_stats(NULL,NULL) AS vfs
ON vfs.database_id = saf.database_id
AND vfs.file_id = saf.file_id
AND saf.database_id NOT IN (1,3,4)
AND saf.type < 2
GROUP BY SUBSTRING(saf.physical_name, 1, 1)
ORDER BY [Диск]
GO
Показать
Производительность журнала транзакций
SELECT (wait_time_ms - signal_wait_time_ms) / waiting_tasks_count AS [Время отклика долговременного носителя журнала (ms)]
, max_wait_time_ms AS [Максимальное время ожидания (ms)]
FROM sys.dm_os_wait_stats
WHERE wait_type = 'WRITELOG' AND waiting_tasks_count > 0;
37.
Sergey.Noskov
133503.11.14 23:38 Сейчас в теме
(17) h00k, Запросы 1 и 2. Усреднение часто поднимает вверх "одиночек", есть риск не увидеть массовые запросы с низким значением [Average CPU used] но высоким [Total CPU used].А их оптимизация дает больший эффект.
Конечно и по средней надо смотреть и по "Итого" и по максимальным значениям, комбинация выборок дает более полную картинку.
(37)Sergey.Noskov Да, возможно это стоило указать в комментариях к запросам. Как-то не пришло в голову что коллеги могут не додуматься изменить опубликованную версию запроса для получения полной картины, и будут довольствоваться только средними показателями.
Многострадальный sys.dm_exec_query_stats можно еще использовать так, топ 30 запросов по длительности блокировки.
SELECT TOP 30
(total_elapsed_time - total_worker_time) / qs.execution_count AS [Average Time Blocked],
total_elapsed_time - total_worker_time AS [Total Time Blocked],
qs.execution_count AS [Execution count],
SUBSTRING (qt.text,qs.statement_start_offset/2,
(CASE WHEN qs.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) AS [Individual Query],
qt.text [Parent Query],
DB_NAME(qt.dbid) AS [Database name]
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
/* этот кусок отберет по базе, если надо по всем - удалить */
/*WHERE DB_NAME(qt.dbid)='ИмяБазы'*/
ORDER BY [Average Time Blocked] DESC;
Наблюдаем за памятью: если Free Pages меньше 300, объем ОЗУ узкое место в производительности системы.
SEL ECT * FR OM sys.sysperfinfo where counter_name like 'Page Writes%' or counter_name like 'Page reads%'
or counter_name like 'lazy%' or counter_name like 'Page Life%' or counter_name like 'Memory Grants Pending%'
or (counter_name = 'Free pages' and [object_name] LIKE '%BUFFER MANAGER%')
Вот бы еще скрипт с интеллектуальным обновлением статистики: обновить статистику только по тем таблицам, где например более 5% измененных записей (как с фрагментацией индексов)
Почему у некоторых запросов из представления dm_exec_query_stats поле total_elapsed_time меньше чем total_worker_time? Подозреваю, что связано с распараллеливанием, но как в таком случае посчитать время ожидания?
Поизучал свои базы и обнаружил, что у таблицы "группы пользователей" сильно нагружен некластерный индекс. А кластерный, более быстрый, простаивает в основном. Вот если я поменяю кластерность, ничем не чревато? Ну, не считая нарушения запретов 1С.
(42) Painted, поменяйте порядок реквизитов в конфигураторе так, чтобы некластерный индекс стал кластерным. Хотя особой разницы в том, какой индекс, нет. Странно то, что индекс вообще используется - если записей сильно меньше 1000, то сканирование дешевле обходится. Или у Вас групп супермного?
(44) Painted, при таком количестве записей индекс получится больше, чем сама таблица, ну и при любых соединениях гарантированно будет использован nested loops из-за малого количества записей
(42) следуя http://msdn.microsoft.com/en-us/library/ms186342.aspx такое возможно. учитывая. что кластерный индекс по умолчанию по первичному ключу, со стороны 1С - при обновлении все вернется на свои места... стоит ли овчинка выделки?
Можете попробовать на копии базы и сравнить производительность
(49) очень грубая оценка. т.к. total_worker_time может быть меньше total_elapsed_time ввиду ожиданий на задержках. Степень параллелизма указывает в ShowPlan statics
(50) Это какого представления колонка "ShowPlan statics" ? Если ты про сам план запроса, то понятно, что там все детально видно. Нужна именно оценка для всего запроса. Понятно, что она будет грубой. Я просто ищу наилучшую.
SELECT TOP 50
OBJECT_NAME(p.objectid, p.dbid) as [object_name]
,qs.execution_count
,qs.total_worker_time
,qs.total_logical_reads
,qs.total_elapsed_time
,CASE statement_end_offset WHEN -1 THEN q.text
ELSE SUBSTRING(q.text, statement_start_offset/2, (statement_end_offset-statement_start_offset)/2) END as sql_statement
,p.query_plan
,q.text
,cp.plan_handle
FROM sys.dm_exec_query_stats qs
INNER JOIN sys.dm_exec_cached_plans cp ON qs.plan_handle = cp.plan_handle
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) p
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) as q
WHERE cp.cacheobjtype = 'Compiled Plan'
AND p.query_plan.value('declare namespace p="http://schemas.microsoft.com/sqlserver/2004/07/showplan";max(//p:RelOp/@Parallel)', 'float') > 0
ORDER BY qs.total_worker_time/qs.execution_count DESC
Показать
WITH cQueryStats
AS (
SELECT qs.plan_handle
,MAX(qs.execution_count) as execution_count
,SUM(qs.total_worker_time) as total_worker_time
,SUM(qs.total_logical_reads) as total_logical_reads
,SUM(qs.total_elapsed_time) as total_elapsed_time
FROM sys.dm_exec_query_stats qs
GROUP BY qs.plan_handle
)
SELECT TOP 50
OBJECT_NAME(p.objectid, p.dbid) as [object_name] ,qs.execution_count
,qs.total_worker_time
,qs.total_logical_reads
,qs.total_elapsed_time
,p.query_plan
,q.text
,cp.plan_handle
FROM cQueryStats qs
INNER JOIN sys.dm_exec_cached_plans cp ON qs.plan_handle = cp.plan_handle
CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) p
CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) as q
WHERE cp.cacheobjtype = 'Compiled Plan'
AND p.query_plan.value('declare namespace p="http://schemas.microsoft.com/sqlserver/2004/07/showplan";max(//p:RelOp/@Parallel)', 'float') > 0
--ORDER BY qs.total_worker_time/qs.execution_count DESC
ORDER BY qs.total_worker_time DESC
запросы к sys.dm_exec_cached_plans (количество adhoc, prepared и др.
select COUNT(*) as adhoc from sys.dm_exec_cached_plans
WHERE objtype = 'ADHOC'
select Count(*) as prepared from sys.dm_exec_cached_plans
WHERE objtype = 'Prepared'
select Count(*) as [Proc] from sys.dm_exec_cached_plans
WHERE objtype = 'Proc'
select Count(*) as [view] from sys.dm_exec_cached_plans
WHERE objtype = 'view'