SQL Profiler и помощник по настройке - PullRequest
7 голосов
/ 25 августа 2009

У нас проблемы с производительностью базы данных, и я имею большой опыт работы с .NET Profilers и всегда выполняю анализ приложения, но, как и многие разработчики, я сейчас жду до позднего вечера (когда это проблема ) начать анализировать и пытаться собрать данные о том, как решить проблему.

Вероятно, это будет не один пост с ответом, а скорее пост "ПОМОГИТЕ Я ИДИОТ БД", в котором вы найдете какие-либо личные рекомендации, рекомендации и опыт в отношении отслеживания проблем.

Что касается настройки, в которой мы используем SQL 2005, у меня очень ограниченный доступ в производственном процессе, чтобы запускать только помощник по настройке ядра СУБД SQL и SQL Profiler через интерфейс портала, я могу копировать и вставлять, но это все. Одна ключевая вещь, которую я хотел бы сделать, это получить точный снимок производственных запросов и вызовов, чтобы я мог загрузить их в механизм настройки в более низкой среде, чтобы попытаться закрепить базу данных, чтобы получить рекомендации по настройке двигателя советник.

Ответы [ 4 ]

7 голосов
/ 26 августа 2009

Этот скрипт может быть использован для определения правильности выбора индексов. Вам нужно посмотреть, как часто индекс используется для поиска, и сравнить его с частотой обновления индекса. Производительность поиска достигается за счет производительности обновления. И что еще хуже, когда индекс часто обновляется, это приводит к фрагментации индекса и устареванию статистики.

Вам также следует сравнить range_scan_count с singleton_lookup_count. Сканирование по дальности является предпочтительным перед поиском синглтона. Поиск по одиночке может быть причиной поиска и поиска по индексу, а также операции поиска по ключу. То есть для каждой строки, найденной в поиске по индексу, sql будет искать страницу данных в кластерном индексе, и это нормально, скажем, пару тысяч, но не для миллионов строк.

CREATE PROCEDURE [ADMIN].[spIndexCostBenefit]
    @dbname [nvarchar](75)
WITH EXECUTE AS CALLER
AS
--set @dbname='Chess'
declare @dbid nvarchar(5)
declare @sql nvarchar(2000)
select @dbid = convert(nvarchar(5),db_id(@dbname))

set @sql=N'select ''object'' = object_name(iu.object_id, iu.database_id)
        , i.name
        ,''user reads'' = iu.user_seeks + iu.user_scans + iu.user_lookups
        ,''system reads'' = iu.system_seeks + iu.system_scans + iu.system_lookups
        ,''user writes'' = iu.user_updates
        ,''system writes'' = iu.system_updates
from '+ @dbname + '.sys.dm_db_index_usage_stats iu
,' + @dbname + '.sys.indexes i
where 
    iu.database_id = ' + @dbid + '
    and iu.index_id=i.index_id
    and iu.object_id=i.object_id
    and (iu.user_seeks + iu.user_scans + iu.user_lookups)<iu.user_updates
order by ''user reads'' desc'

exec sp_executesql @sql

set @sql=N'SELECT
   ''object'' = object_name(o.object_id, o.database_id),
   o.index_id,
   ''usage_reads'' = user_seeks + user_scans + user_lookups,
   ''operational_reads'' = range_scan_count + singleton_lookup_count,
   range_scan_count,
   singleton_lookup_count,
   ''usage writes'' = user_updates,
   ''operational_leaf_writes'' = leaf_insert_count + leaf_update_count + leaf_delete_count,
   leaf_insert_count,
   leaf_update_count,
   leaf_delete_count,
   ''operational_leaf_page_splits'' = leaf_allocation_count,
   ''operational_nonleaf_writes'' = nonleaf_insert_count + nonleaf_update_count + nonleaf_delete_count,
   ''operational_nonleaf_page_splits'' = nonleaf_allocation_count
FROM
   ' + @dbname + '.sys.dm_db_index_operational_stats(' + @dbid + ', NULL, NULL, NULL) o,
   ' + @dbname + '.sys.dm_db_index_usage_stats u
WHERE
   u.object_id = o.object_id
   AND u.index_id = o.index_id
ORDER BY
   operational_reads DESC,
   operational_leaf_writes,
   operational_nonleaf_writes'

exec sp_executesql @sql

GO
5 голосов
/ 25 августа 2009

Если вы можете использовать профилировщик для хранения событий в таблице, то нет проблем с использованием помощника по настройке базы данных (DTA) для оптимизации базы данных из таблицы журнала, но лично я вообще не использую DTA , Использование DTA занимает много времени, и я хочу больше контролировать происходящее.

Если вы можете убедить владельца сервера создать новую базу данных, которая называется что-то вроде «SQLToolkit», и дать вам права на выполнение процедур, у меня есть пара процедур, которые помогут вам выбрать правильные индексы.

    CREATE PROCEDURE [ADMIN].[spMissingIndexes]
AS
SELECT
      mid.statement,
      mid.equality_columns,
      mid.inequality_columns,
      mid.included_columns,
      migs.user_seeks,
      migs.user_scans,
      migs.last_user_seek,
      migs.avg_user_impact,
      user_scans,
      avg_total_user_cost,
      avg_total_user_cost * avg_user_impact * (user_seeks + user_scans) AS [weight]--, migs.*--, mid.*
   FROM
      sys.dm_db_missing_index_group_stats AS migs
      INNER JOIN sys.dm_db_missing_index_groups AS mig
         ON (migs.group_handle = mig.index_group_handle)
      INNER JOIN sys.dm_db_missing_index_details AS mid
         ON (mig.index_handle = mid.index_handle)
   ORDER BY
      avg_total_user_cost * avg_user_impact * (user_seeks + user_scans) DESC ;

GO
4 голосов
/ 26 августа 2009

По запросу я отправляю еще один полезный скрипт, чтобы определить, как часто и как долго блокируется любой индекс из-за механизма блокировки в SQL:

CREATE PROCEDURE [ADMIN].[spIndexContention]
    @dbname sysname
WITH EXECUTE AS CALLER
AS
declare @dbid int
select @dbid = DB_ID(@dbname)
declare @sql nvarchar(1000)
SET @sql = N'SELECT dbname=DB_NAME(database_id), tablename=object_name(s.object_id, s.database_id)
    , indexname=i.name, i.index_id
    , row_lock_count, row_lock_wait_count
    , [block %]=cast (100.0 * row_lock_wait_count / (1 + row_lock_count) as numeric(15,2))
    , row_lock_wait_in_ms
    , [avg row lock waits in ms]=cast (1.0 * row_lock_wait_in_ms / (1 + row_lock_wait_count) as numeric(15,2))
FROM sys.dm_db_index_operational_stats (' + convert(nvarchar(5),@dbid) + ', NULL, NULL, NULL) s
    INNER JOIN ' + @dbname + N'.sys.indexes i 
        ON i.object_id = s.object_id
        AND i.index_id = s.index_id
ORDER BY row_lock_wait_count desc'
print @sql
exec sp_executesql @sql


GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...