【问题标题】:SQL Profiler and Tuning AdvisorSQL 探查器和调优顾问
【发布时间】:2010-11-22 14:32:36
【问题描述】:

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

这可能不会是一个单一答案的帖子,而更像是一个“帮助我是数据库白痴”的帖子,并寻找任何方向的个人建议、建议和如何追踪问题的经验。

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

【问题讨论】:

    标签: sql performance


    【解决方案1】:
    【解决方案2】:

    如果您可以使用分析器将事件存储到表中,那么使用数据库优化顾问 (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】:

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

    【讨论】:

      【解决方案4】:

      此脚本可用于确定您是否选择了正确的索引。您需要查看索引用于查找的频率,并将其与索引的更新频率进行比较。寻求性能是以更新性能为代价的。更糟糕的是,当索引频繁更新时,会导致索引碎片化,统计信息过时。

      您还应该将 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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-03
        相关资源
        最近更新 更多