Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL分析器和调优顾问_Sql_Performance - Fatal编程技术网

SQL分析器和调优顾问

SQL分析器和调优顾问,sql,performance,Sql,Performance,我们在数据库性能方面遇到了问题,我有很多使用.NET Profiler的经验,并且总是在应用程序上执行分析,但就像很多开发人员一样,我现在一直等到很晚(当出现问题时)才开始分析并试图收集有关如何解决问题的数据 这可能不是一篇只有一个答案的帖子,而是一篇“帮助我,我是一个DB白痴”的帖子,寻找关于如何追踪问题的个人建议、建议和经验 至于我们使用SQL 2005的设置,我在生产中的访问权限非常有限,只能通过门户界面运行SQL数据库引擎优化顾问和SQL Profiler,我可以复制和粘贴,仅此而已。我

我们在数据库性能方面遇到了问题,我有很多使用.NET Profiler的经验,并且总是在应用程序上执行分析,但就像很多开发人员一样,我现在一直等到很晚(当出现问题时)才开始分析并试图收集有关如何解决问题的数据

这可能不是一篇只有一个答案的帖子,而是一篇“帮助我,我是一个DB白痴”的帖子,寻找关于如何追踪问题的个人建议、建议和经验


至于我们使用SQL 2005的设置,我在生产中的访问权限非常有限,只能通过门户界面运行SQL数据库引擎优化顾问和SQL Profiler,我可以复制和粘贴,仅此而已。我想做的一件关键事情是获得生产查询和调用的真实快照,这样我就可以在一个较低的环境中将它们加载到优化引擎中,我可以尝试锁定数据库,这样我就可以从引擎优化顾问那里获得建议。

以下是一些链接,可以帮助您开始追求性能


如果您可以使用探查器将事件存储到一个表中,那么使用数据库调优顾问(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

根据请求,我将发送另一个有用的脚本,以确定由于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

此脚本可用于确定是否选择了正确的索引。您需要查看索引用于seek的频率,并将其与索引更新的频率进行比较。搜索性能是以更新性能为代价的。更糟糕的是,当索引频繁更新时,会导致索引支离破碎,统计数据过时

您还应该比较范围\u扫描\u计数和单例\u查找\u计数。在单例查找之前,首选范围扫描。单例查找可能是索引查找和键查找操作的原因。也就是说,对于在索引搜索中找到的每一行,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
创建过程[ADMIN]。[spIndexCostBenefit]
@dbname[nvarchar](75)
以EXECUTE作为调用方
作为
--设置@dbname='Chess'
声明@dbid nvarchar(5)
声明@sql nvarchar(2000年)
选择@dbid=convert(nvarchar(5),db_id(@dbname))
set@sql=N'选择“对象”=对象名称(iu.object\u id,iu.database\u id)
,即姓名
,“用户读取”=iu.user\u查找+iu.user\u扫描+iu.user\u查找
,“系统读取”=iu.system\u查找+iu.system\u扫描+iu.system\u查找
,“用户写入”=iu.user\u更新
,“系统写入”=iu.system\U更新
从'+@dbname+'.sys.dm_db_index_usage_stats iu
,'+@dbname+'.sys.index i
哪里
iu.database_id='+@dbid+'
和iu.index\u id=i.index\u id
和iu.object\u id=i.object\u id

(iu.user\u seeks+iu.user\u scans+iu.user\u lookup)这太棒了,谢谢!如果你有任何其他的,你不介意分享,我很乐意看到他们。再次感谢你!这些链接是完美的!非常感谢。