我们遇到了数据库性能方面的问题,而且我对.NET Profilers有很多经验并且总是在应用程序上执行分析,但很多开发人员现在都在等待,直到很晚(当它出现问题时) )开始分析并尝试收集有关如何解决问题的数据。
这可能不是一个单独的回答帖子,更多的是“帮助我是一个DB IDII”帖子,并寻找任何方向的个人建议,建议和如何追踪问题的经验。
就我们使用SQL 2005的设置而言,我在生产中的访问权限非常有限,只能通过门户界面运行SQL数据库引擎优化顾问和SQL事件探查器,我可以复制和粘贴,但这就是它。我想要做的一件事是获得生产查询和调用的真实快照,这样我就可以在较低的环境中将它们加载到调优引擎中,我可以尝试修改数据库,以便我可以从引擎调整中获取建议顾问。
答案 0 :(得分:7)
此脚本可用于确定您是否选择了正确的索引。您需要查看索引用于搜索的频率,并将其与索引更新的频率进行比较。寻求性能是以更新性能为代价的。更糟糕的是,当索引频繁更新时,会导致索引碎片化并且统计信息过时。
您还应该将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
答案 1 :(得分:5)
以下是一些可以帮助您开始追求绩效的链接。
What resources exist for Database performance-tuning?
Favourite performance tuning tricks
What generic techniques can be applied to optimize SQL queries?
Best way to improve performance (and include somehow failover)
答案 2 :(得分:5)
如果您可以使用分析器将事件存储到表中,那么使用数据库调整顾问程序(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
答案 3 :(得分:4)
根据请求,我发送另一个有用的脚本来确定由于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