• SQL常用性能相关脚本


    --调试语句性能前记得清空执行计划

    每次执行需优化SQL前,带上清除缓存的设置SQL。

    平常在进行SQL Server性能优化时,为了确保真实还原性能问题,我们需要关闭SQL Server自身的执行计划及缓存。可以通过以下设置清除缓存。

    1 DBCC DROPCLEANBUFFERS  --清除缓冲区
    2 DBCC FREEPROCCACHE  --删除计划高速缓存中的元素

    开启查询IO读取统计、查询时间统计。

    SET STATISTICS TIME ON --执行时间
    SET STATISTICS IO ON --IO读取


    --查询当前的事务

    select 
    t2.session_id as SPID,
    t2.transaction_id,
    transaction_begin_time,
    N'已执行'+ltrim(datediff(mi,transaction_begin_time,getdate()))+N'分钟' as mi,
    case transaction_type 
    when 1 then N'读/写事务' 
    when 2 then N'只读事务' 
    when 3 then N'系统事务' 
    when 4 then N'分布式事务' end tran_Type,
    case transaction_state
    when 0 then N'事务尚未完全初始化'
    when 1 then N'事务已初始化但尚未启动'
    when 2 then N'事务处于活动状态'
    when 3 then N'事务已结束。该状态用于只读事务'
    when 4 then N'已对分布式事务启动提交进程'
    when 5 then N'事务处于准备就绪状态且等待解析'
    when 6 then N'事务已提交'
    when 7 then N'事务正在被回滚'
    when 0 then N'事务已回滚'
    end transaction_state,
    client_net_address,
    client_tcp_port,
    program_name,
    t2.text
    
    from
    sys.dm_tran_active_transactions t1 join (
    select 
    a.session_id,
    transaction_id,
    client_net_address,
    client_tcp_port,
    text,c.program_name
    from sys.dm_tran_session_transactions a join (
    select session_id,a2.text,client_net_address,client_tcp_port from sys.dm_exec_connections a1
    cross apply sys.dm_exec_sql_text(a1.most_recent_sql_Handle) a2
    ) b on a.session_id=b.session_id
    left join sys.dm_exec_sessions c on a.session_id=c.session_id
    where is_user_transaction=1
    )t2 on t1.transaction_ID=t2.transaction_ID
    ORDER BY t2.transaction_id
    View Code
     
    --死锁相关,转自http://www.blogjava.net/parable-myth/archive/2007/10/15/153010.html
    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_lockinfo]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
    drop procedure [dbo].[p_lockinfo]
    GO
    
    SET QUOTED_IDENTIFIER ON 
    GO
    SET ANSI_NULLS ON 
    GO
    
    
    /*--处理死锁
    
     查看当前进程,或死锁进程,并能自动杀掉死进程
    
     因为是针对死的,所以如果有死锁进程,只能查看死锁进程
     当然,你可以通过参数控制,不管有没有死锁,都只查看死锁进程
    
     感谢: caiyunxia,jiangopen 两位提供的参考信息
    
    --邹建 2004.4--*/
    
    /*--调用示例
    
     exec p_lockinfo
    --*/
    create proc p_lockinfo
    @kill_lock_spid bit=1,  --是否杀掉死锁的进程,1 杀掉, 0 仅显示
    @show_spid_if_nolock bit=1 --如果没有死锁的进程,是否显示正常进程信息,1 显示,0 不显示
    as
    declare @count int,@s nvarchar(1000),@i int
    select id=identity(int,1,1),标志,
     进程ID=spid,线程ID=kpid,块进程ID=blocked,数据库ID=dbid,
     数据库名=db_name(dbid),用户ID=uid,用户名=loginame,累计CPU时间=cpu,
     登陆时间=login_time,打开事务数=open_tran, 进程状态=status,
     工作站名=hostname,应用程序名=program_name,工作站进程ID=hostprocess,
     域名=nt_domain,网卡地址=net_address
    into #t from(
     select 标志='死锁的进程',
      spid,kpid,a.blocked,dbid,uid,loginame,cpu,login_time,open_tran,
      status,hostname,program_name,hostprocess,nt_domain,net_address,
      s1=a.spid,s2=0
     from master..sysprocesses a join (
      select blocked from master..sysprocesses group by blocked
      )b on a.spid=b.blocked where a.blocked=0
     union all
     select '|_牺牲品_>',
      spid,kpid,blocked,dbid,uid,loginame,cpu,login_time,open_tran,
      status,hostname,program_name,hostprocess,nt_domain,net_address,
      s1=blocked,s2=1
     from master..sysprocesses a where blocked<>0
    )a order by s1,s2
    
    select @count=@@rowcount,@i=1
    
    if @count=0 and @show_spid_if_nolock=1
    begin
     insert #t
     select 标志='正常的进程',
      spid,kpid,blocked,dbid,db_name(dbid),uid,loginame,cpu,login_time,
      open_tran,status,hostname,program_name,hostprocess,nt_domain,net_address
     from master..sysprocesses
     set @count=@@rowcount
    end
    
    if @count>0
    begin
     create table #t1(id int identity(1,1),a nvarchar(30),b Int,EventInfo nvarchar(255))
     if @kill_lock_spid=1
     begin
      declare @spid varchar(10),@标志 varchar(10)
      while @i<=@count
      begin
       select @spid=进程ID,@标志=标志 from #t where id=@i
       insert #t1 exec('dbcc inputbuffer('+@spid+')')
       if @标志='死锁的进程' exec('kill '+@spid)
       set @i=@i+1
      end
     end
     else
      while @i<=@count
      begin
       select @s='dbcc inputbuffer('+cast(进程ID as varchar)+')' from #t where id=@i
       insert #t1 exec(@s)
       set @i=@i+1
      end
     select a.*,进程的SQL语句=b.EventInfo
     from #t a join #t1 b on a.id=b.id
    end
    
    GO
    SET QUOTED_IDENTIFIER OFF 
    GO
    SET ANSI_NULLS ON 
    GO
    View Code
    ----索引执行情况
    
    SELECT objects.name ,
    databases.name ,
    indexes.name ,
    user_seeks ,
    user_scans ,
    user_lookups ,
    partition_stats.row_count
    FROM sys.dm_db_index_usage_stats stats
    LEFT JOIN sys.objects objects ON stats.object_id = objects.object_id
    LEFT JOIN sys.databases databases ON databases.database_id = stats.database_id
    LEFT JOIN sys.indexes indexes ON indexes.index_id = stats.index_id
    AND stats.object_id = indexes.object_id
    LEFT JOIN sys.dm_db_partition_stats partition_stats ON stats.object_id = partition_stats.object_id
    AND indexes.index_id = partition_stats.index_id
    WHERE 1 = 1
    --AND databases.database_id = 7
    AND objects.name IS NOT NULL
    AND indexes.name IS NOT NULL
    AND user_scans>0
    ORDER BY user_scans DESC ,stats.object_id ,indexes.index_id
    View Code
    
    
    ----最占用CPU
    
    SELECT TOP 100 execution_count,
    total_logical_reads /execution_count AS [Avg Logical Reads],
    total_elapsed_time /execution_count AS [Avg Elapsed Time],
    db_name(st.dbid) as [database name],
    object_name(st.dbid) as [object name],
    object_name(st.objectid) as [object name 1],
    SUBSTRING(st.text, (qs.statement_start_offset / 2) + 1, 
    ((CASE statement_end_offset WHEN - 1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset) 
    / 2) + 1) AS statement_text
    FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
    WHERE execution_count > 100 AND qs.creation_time > dateadd(day,-3,getdate())
    ORDER BY 1 DESC;
    View Code


    ---执行时间最长的命令
    
    
    SELECT TOP 10 COALESCE(DB_NAME(st.dbid),
    DB_NAME(CAST(pa.value as int))+'*','Resource') AS DBNAME,
    SUBSTRING(text,
    -- starting value for substring
    CASE WHEN statement_start_offset = 0
    OR statement_start_offset IS NULL
    THEN 1
    ELSE statement_start_offset/2 + 1 END,
    -- ending value for substring
    CASE WHEN statement_end_offset = 0
    OR statement_end_offset = -1
    OR statement_end_offset IS NULL
    THEN LEN(text)
    ELSE statement_end_offset/2 END -
    CASE WHEN statement_start_offset = 0
    OR statement_start_offset IS NULL
    THEN 1
    ELSE statement_start_offset/2 END + 1
    ) AS TSQL,
    total_logical_reads/execution_count AS AVG_LOGICAL_READS
    FROM sys.dm_exec_query_stats
    CROSS APPLY sys.dm_exec_sql_text(sql_handle) st
    OUTER APPLY sys.dm_exec_plan_attributes(plan_handle) pa
    WHERE attribute = 'dbid'
    ORDER BY AVG_LOGICAL_READS DESC ;
    View Code
    
    
    ----缺索引
    
    
    SELECT TOP 30
    [Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0)
    , avg_user_impact, TableName = statement, [EqualityUsage] = equality_columns
    , [InequalityUsage] = inequality_columns, [Include Cloumns] = included_columns
    FROM sys.dm_db_missing_index_groups g
    INNER JOIN sys.dm_db_missing_index_group_stats s
    ON s.group_handle = g.index_group_handle
    INNER JOIN sys.dm_db_missing_index_details d
    ON d.index_handle = g.index_handle
    ORDER BY [Total Cost] DESC;
    View Code
    
    
    
    --经常更新却很少使用的索引
    
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
    SELECT 
    DB_NAME() AS DatabaseName 
    , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
    , OBJECT_NAME(s.[object_id]) AS TableName 
    , i.name AS IndexName 
    , s.user_updates 
    , s.system_seeks + s.system_scans + s.system_lookups 
    AS [System usage] 
    INTO #TempUnusedIndexes 
    FROM sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
    AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id 
    WHERE 1=2 
    EXEC sp_MSForEachDB 'USE [?]; 
    INSERT INTO #TempUnusedIndexes 
    SELECT TOP 20 
    DB_NAME() AS DatabaseName 
    , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
    , OBJECT_NAME(s.[object_id]) AS TableName 
    , i.name AS IndexName 
    , s.user_updates 
    , s.system_seeks + s.system_scans + s.system_lookups 
    AS [System usage] 
    FROM sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
    AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id 
    WHERE s.database_id = DB_ID() 
    AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0 
    AND s.user_seeks = 0 
    AND s.user_scans = 0 
    AND s.user_lookups = 0 
    AND i.name IS NOT NULL 
    ORDER BY s.user_updates DESC' 
    SELECT TOP 20 * FROM #TempUnusedIndexes
    WHERE DatabaseName = 'agilepoint50' ORDER BY [user_updates] DESC 
    DROP TABLE #TempUnusedIndexes
    View Code
    
    
    
    ---维护代价最高的索引
    
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
    SELECT 
    DB_NAME() AS DatabaseName 
    , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
    , OBJECT_NAME(s.[object_id]) AS TableName 
    , i.name AS IndexName 
    , (s.user_updates ) AS [update usage] 
    , (s.user_seeks + s.user_scans + s.user_lookups) AS [Retrieval usage] 
    , (s.user_updates) - 
    (s.user_seeks + s.user_scans + s.user_lookups) AS [Maintenance cost] 
    , s.system_seeks + s.system_scans + s.system_lookups AS [System usage] 
    , s.last_user_seek 
    , s.last_user_scan 
    , s.last_user_lookup 
    INTO #TempMaintenanceCost 
    FROM sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
    AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id 
    WHERE 1=2 
    EXEC sp_MSForEachDB 'USE [?]; 
    INSERT INTO #TempMaintenanceCost 
    SELECT TOP 20 
    DB_NAME() AS DatabaseName 
    , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
    , OBJECT_NAME(s.[object_id]) AS TableName 
    , i.name AS IndexName 
    , (s.user_updates ) AS [update usage] 
    , (s.user_seeks + s.user_scans + s.user_lookups) 
    AS [Retrieval usage] 
    , (s.user_updates) - 
    (s.user_seeks + user_scans + 
    s.user_lookups) AS [Maintenance cost] 
    , s.system_seeks + s.system_scans + s.system_lookups AS [System usage] 
    , s.last_user_seek 
    , s.last_user_scan 
    , s.last_user_lookup 
    FROM sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
    AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id 
    WHERE s.database_id = DB_ID() 
    AND i.name IS NOT NULL 
    AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0 
    AND (s.user_seeks + s.user_scans + s.user_lookups) > 0 
    ORDER BY [Maintenance cost] DESC' 
    SELECT top 20 * FROM #TempMaintenanceCost WHERE DatabaseName ='agilepoint50' ORDER BY [Maintenance cost] DESC 
    DROP TABLE #TempMaintenanceCost
    View Code
    
    
    
    ---表及数据库的空间占用
    
    set nocount on
    declare @db varchar(20)
    set @db = db_name()
    dbcc updateusage(@db) with no_infomsgs
    go
    
    create table #tblspace
    (
    
    数据表名称 varchar(50) null,
    记录笔数 int null,
    保留空间 varchar(15) null,
    数据使用空间 varchar(15) null,
    索引使用空间 varchar(15) null,
    未使用空间 varchar(15) null,
    
    )
    declare @tblname varchar(50)
    declare curtbls cursor for
    select table_name from information_schema.tables
    where table_type = 'base table'
    open curtbls
    Fetch next from curtbls into @tblname
    while @@fetch_status = 0
    begin
    insert #tblspace exec sp_spaceused @tblname
    fetch next from curtbls into @tblname
    end
    close curtbls
    deallocate curtbls
    
    select * from #tblspace order by
    convert(int,left(保留空间,len(保留空间)-2)) desc
    drop table #tblspace
    View Code
    
    
    
    
    

     --检测死锁

    --如果发生死锁了,我们怎么去检测具体发生死锁的是哪条SQL语句或存储过程?

    
    --这时我们可以使用以下存储过程来检测,就可以查出引起死锁的进程和SQL语句。SQL Server自带的系统存储过程sp_who和sp_lock也可以用来查找阻塞和死锁, 但没有这里介绍的方法好用。

    use master
    
    go
    
    create procedure sp_who_lock
    
    as
    
    begin
    
    declare @spid int,@bl int,
    
     @intTransactionCountOnEntry  int,
    
            @intRowcount    int,
    
            @intCountProperties   int,
    
            @intCounter    int
    
    
    
     create table #tmp_lock_who (
    
     id int identity(1,1),
    
     spid smallint,
    
     bl smallint)
    
     
    
     IF @@ERROR<>0 RETURN @@ERROR
    
     
    
     insert into #tmp_lock_who(spid,bl) select  0 ,blocked
    
       from (select * from sysprocesses where  blocked>0 ) a 
    
       where not exists(select * from (select * from sysprocesses where  blocked>0 ) b 
    
       where a.blocked=spid)
    
       union select spid,blocked from sysprocesses where  blocked>0
    
    
    
     IF @@ERROR<>0 RETURN @@ERROR 
    
      
    
    -- 找到临时表的记录数
     select  @intCountProperties = Count(*),@intCounter = 1
    
     from #tmp_lock_who
    
     
    
     IF @@ERROR<>0 RETURN @@ERROR 
    
     
    
     if @intCountProperties=0
    
      select '现在没有阻塞和死锁信息' as message
    
    
    
    -- 循环开始
    while @intCounter <= @intCountProperties
    
    begin
    
    -- 取第一条记录
      select  @spid = spid,@bl = bl
    
      from #tmp_lock_who where Id = @intCounter 
    
     begin
    
      if @spid =0 
    
                select '引起数据库死锁的是: '+ CAST(@bl AS VARCHAR(10)) + '进程号,其执行的SQL语法如下'
    
     else
    
                select '进程号SPID:'+ CAST(@spid AS VARCHAR(10))+ '' + '进程号SPID:'+ CAST(@bl AS VARCHAR(10)) +'阻塞,其当前进程执行的SQL语法如下'
    
     DBCC INPUTBUFFER (@bl )
    
     end 
    
    
    
    -- 循环指针下移
     set @intCounter = @intCounter + 1
    
    end
    
    
    
    drop table #tmp_lock_who
    
    
    
    return 0
    
    end
    View Code
    
    --杀死锁和进程

    --如何去手动的杀死进程和锁?最简单的办法,重新启动服务。但是这里要介绍一个存储过程,通过显式的调用,可以杀死进程和锁。

    use master
    
    go
    
    
    
    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[p_killspid]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
    
    drop procedure [dbo].[p_killspid]
    
    GO
    
    
    
    create proc p_killspid
    
    @dbname varchar(200)    --要关闭进程的数据库名
    as  
    
        declare @sql  nvarchar(500)  
    
        declare @spid nvarchar(20)
    
    
    
        declare #tb cursor for
    
            select spid=cast(spid as varchar(20)) from master..sysprocesses where dbid=db_id(@dbname)
    
        open #tb
    
        fetch next from #tb into @spid
    
        while @@fetch_status=0
    
        begin  
    
            exec('kill '+@spid)
    
            fetch next from #tb into @spid
    
        end  
    
        close #tb
    
        deallocate #tb
    
    go
    View Code


    --用法
    exec p_killspid 'newdbpy'

    --查看锁信息

    --如何查看系统中所有锁的详细信息?在企业管理管理器中,我们可以看到一些进程和锁的信息,这里介绍另外一种方法。

    create table #t(req_spid int,obj_name sysname)
    
    
    
    declare @s nvarchar(4000)
    
        ,@rid int,@dbname sysname,@id int,@objname sysname
    
    
    
    declare tb cursor for 
    
        select distinct req_spid,dbname=db_name(rsc_dbid),rsc_objid
    
        from master..syslockinfo where rsc_type in(4,5)
    
    open tb
    
    fetch next from tb into @rid,@dbname,@id
    
    while @@fetch_status=0
    
    begin
    
        set @s='select @objname=name from ['+@dbname+']..sysobjects where id=@id'
    
        exec sp_executesql @s,N'@objname sysname out,@id int',@objname out,@id
    
        insert into #t values(@rid,@objname)
    
        fetch next from tb into @rid,@dbname,@id
    
    end
    
    close tb
    
    deallocate tb
    
    
    
    select 进程id=a.req_spid
    
        ,数据库=db_name(rsc_dbid)
    
        ,类型=case rsc_type when 1 then 'NULL 资源(未使用)'
    
            when 2 then '数据库'
    
            when 3 then '文件'
    
            when 4 then '索引'
    
            when 5 then ''
    
            when 6 then ''
    
            when 7 then ''
    
            when 8 then '扩展盘区'
    
            when 9 then 'RID(行 ID)'
    
            when 10 then '应用程序'
    
        end
    
        ,对象id=rsc_objid
    
        ,对象名=b.obj_name
    
        ,rsc_indid
    
     from master..syslockinfo a left join #t b on a.req_spid=b.req_spid
    
    
    
    go
    
    drop table #t
    View Code
     重置所有索引
    USE xxxx; 
    DECLARE @name varchar(100)
    
    DECLARE authors_cursor CURSOR FOR  Select [name]   from sysobjects where xtype='u' order by id
    
    OPEN authors_cursor
    
    FETCH NEXT FROM authors_cursor  INTO @name
    
    WHILE @@FETCH_STATUS = 0 
    BEGIN    
    
     DBCC DBREINDEX (@name, '', 90)
    
     FETCH NEXT FROM authors_cursor     INTO @name 
    END
    
    deallocate authors_cursor
     
  • 相关阅读:
    记第一场省选
    POJ 2083 Fractal 分形
    CodeForces 605A Sorting Railway Cars 思维
    FZU 1896 神奇的魔法数 dp
    FZU 1893 内存管理 模拟
    FZU 1894 志愿者选拔 单调队列
    FZU 1920 Left Mouse Button 简单搜索
    FZU 2086 餐厅点餐
    poj 2299 Ultra-QuickSort 逆序对模版题
    COMP9313 week4a MapReduce
  • 原文地址:https://www.cnblogs.com/ceci/p/4565437.html
Copyright © 2020-2023  润新知