• 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
     
  • 相关阅读:
    MicroPython的开发板
    python 安装mysql报错
    30个mysql千万级大数据SQL查询优化技巧详解
    PHP针对数字的加密解密类,可直接使用
    form表单公用
    生成随机邀请码
    Tp5自动验证
    protected和private的区别
    中国俗语大全
    更改Unity项目新建模板
  • 原文地址:https://www.cnblogs.com/ceci/p/4565437.html
Copyright © 2020-2023  润新知