楼主: Cherish_j_wang

[精华] MSSQL DBA 精华总结[处理对象名称中特殊字符]

[复制链接]
论坛徽章:
14
迷宫蛋
日期:2012-03-13 09:50:292014年新春福章
日期:2014-02-18 16:44:08优秀写手
日期:2013-12-18 09:29:15迷宫蛋
日期:2012-06-13 15:28:34咸鸭蛋
日期:2012-06-11 16:11:11灰彻蛋
日期:2012-05-31 10:18:54双黄蛋
日期:2012-05-28 17:45:17茶鸡蛋
日期:2012-05-28 17:27:32蜘蛛蛋
日期:2012-05-28 16:54:09迷宫蛋
日期:2012-05-17 19:00:48
41#
 楼主| 发表于 2012-3-12 17:32 | 只看该作者
本帖最后由 Cherish_j_wang 于 2012-3-12 17:43 编辑

MSSQL DBA精华总结

之DeadLock Graph Trace文件分析

场景

在MSSQL DBA的工作中,经常会有DeadLock的原因分析的案例。本文的目的在于使用SQL脚本获取DeadLock Graph Trace文件的信息,从而达到对DeadLock的原因分析的目的。

前提 Deadlock_testing.sql (8.4 KB, 下载次数: 60)
在本次分享开始之前,我们首先必须要用MSSQL ProfilerDeadLock Graph的Trace文件,你可要从本文的附件中下载(Deadlock_testing.sql,然后将后缀名修改为trc),也可要使用下面的方法来自己生成。
1.      开启MSSQL Profiler:开始->运行->键入profiler
2.      Trace DeadLock Graph Event:在Profiler窗体中,开启一个Trace->显示所有事件->依次找到Locks->DeadLocak Graph->运行(参见下面的截图,按照字母标号依次点击即可)
注:
我们仅Trace这一个事件就好了,请取消其他无用的多余事件。
3.      在MSSQL中创建测试所要使用到的表

  1. use test
  2. GO

  3. if OBJECT_ID('dbo.test_deadlock1','u') is not null
  4.         drop table dbo.test_deadlock1
  5. go

  6. create table dbo.test_deadlock1(
  7. id int identity(1,1) not null primary key
  8. ,name varchar(20) null
  9. );

  10. if OBJECT_ID('dbo.test_deadlock2','u') is not null
  11.         drop table dbo.test_deadlock2
  12. go

  13. create table dbo.test_deadlock2(
  14. id int identity(1,1) not null primary key
  15. ,name varchar(20) null
  16. );
  17. GO

  18. insert into dbo.test_deadlock1
  19. select 'AA'
  20. UNION ALL
  21. select 'BB';


  22. insert into dbo.test_deadlock2
  23. select 'AA'
  24. UNION ALL
  25. select 'BB';
  26. GO
复制代码


4.      开启一个MSSQL连接(比如SPID为53),在这个连接中执行下面的语句

  1. use test
  2. GO

  3. begin tran
  4. update dbo.test_deadlock1
  5. set name = 'CC'
  6. where id = 1
  7. ;
  8. waitfor delay '00:00:05'
  9. update dbo.test_deadlock2
  10. set name = 'CC'
  11. where id = 1
  12. ;
  13. rollback
复制代码

5.      再打开另外一个MSSQL连接(比如SPID为54),在此连接中执行下面的语句(4,5之间执行的事件差不要超过5秒)

  1. use test
  2. GO

  3. begin tran
  4. update dbo.test_deadlock2
  5. set name = 'CC'
  6. where id = 1
  7. ;

  8. update dbo.test_deadlock1
  9. set name = 'CC'
  10. where id = 1
  11. ;
  12. commit
复制代码

6.      查看Profiler中的DeadLock Graph Trace到的信息,如下图所示:
7.      保存Trace信息,参加下图:比如将Trace信息保存到I:\Temp\Deadlock_testing.trc

脚本
DeadLockGraph_analysis.sql (2.98 KB, 下载次数: 49)
在Deadlock_testing.trc文件生成后,接下来最重要的事情就是对这个文件进行分析了,那么如何对一个Trace文件进行分析呢?这个就是我们今天需要分享的重点了,前面的篇幅都是铺垫。我们讲,我们的目的使用SQL脚本对这个文件进行分析,话不多说了,直接上脚本:
  1. use master
  2. go

  3. -- declare variables.
  4. declare
  5.         @file nvarchar(256)
  6. ;
  7. select
  8.         @file = N'I:\Temp\Deadlock_testing.trc'
  9. ;

  10. WITH DATA
  11. AS
  12. (
  13.         /*
  14.         SELECT
  15.                         RowNumber = row_number() OVER (ORDER BY StartTime)
  16.                         ,DeadlockGraph = CAST(TextData AS xml)
  17.                         ,StartTime
  18.                         ,spid
  19.         FROM test.dbo.Deadlock_testing WITH (NOLOCK)
  20.         WHERE EventClass = 148*/
  21.         
  22.         SELECT
  23.                 --[TraceID] = @trace_id ,
  24.                 RowNumber = row_number() OVER (ORDER BY StartTime), -- assign a row number to each deadlock
  25.                 [DeadlockGraph]=case when TextData like '<deadlock-list%' then convert(xml, TextData) else null end,
  26.                 *
  27.         from ::fn_trace_gettable(@file, default)
  28.         where TextData like '<deadlock-list%'
  29. )
  30. ,
  31. deadlock
  32. AS
  33. (
  34.         SELECT
  35.                         RowNumber
  36.                         ,OwnerID = T.C.value('@id', 'varchar(50)')
  37.                         ,SPid = T.C.value('(./@spid)[1]','int')
  38.                         ,status = T.C.value('(./@status)[1]','varchar(10)')
  39.                         --,PagelockObject = T.C.value('/deadlock-list[1]/deadlock[1]/resource-list[1]/pagelock[1]/@objectname', 'varchar(200)')
  40.                         --,DeadlockObject = T.C.value('/deadlock-list[1]/deadlock[1]/resource-list[1]/objectlock[1]/@objectname', 'varchar(200)')
  41.                         --,KeylockObject = T.C.value('/deadlock-list[1]/deadlock[1]/resource-list[1]/pagelock[1]/@objectname', 'varchar(200)')
  42.                         --,DeadlockObject = T.C.value('/deadlock-list[1]/deadlock[1]/resource-list[1]/objectlock[1]/@objectname', 'varchar(200)')
  43.                         ,Victim = case when T.C.value('@id', 'varchar(50)') = T.C.value('./../../@victim','varchar(50)') then 1 else 0 end
  44.                         ,LockMode = T.C.value('@lockMode', 'varchar(20)')
  45.                         ,DeadlockGraph
  46.                         ,Inputbuf = T.C.value('(./inputbuf/text())[1]','varchar(max)')
  47.                         ,Code = T.C.value('(./executionStack/frame/text())[1]','VARCHAR(max)')
  48.                         ,SPName = T.C.value('(./executionStack/frame/@procname)[1]','sysname')
  49.                         ,Hostname = T.C.value('(./@hostname)[1]','sysname')
  50.                         ,Clientapp = T.C.value('(./@clientapp)[1]','varchar(max)')
  51.                         ,LoginName = T.C.value('@loginname', 'varchar(20)')
  52.                         ,Action = T.C.value('(./@transactionname)[1]','varchar(max)')
  53.                         ,StartTime
  54.                         ,TransactionTime = T.C.value('@lasttranstarted', 'datetime')
  55.                         --,*
  56.         FROM DATA AS A
  57.                 CROSS APPLY DeadlockGraph.nodes('deadlock-list/deadlock/process-list/process') AS T(C)
  58. )
  59. ,
  60. keylock
  61. AS
  62. (
  63.         SELECT
  64.                 OwnerID = T.C.value('./owner[1]/@id', 'varchar(50)')
  65.                 ,KeylockObject = T.C.value('./../@objectname', 'varchar(200)')
  66.                 ,Indexname = T.C.value('./../@indexname', 'varchar(200)')
  67.                 ,IndexLockMode = T.C.value('./../@mode', 'varchar(20)')
  68.                 --,owner = T.C.query('.')
  69.         FROM DATA AS A
  70.                 CROSS APPLY DeadlockGraph.nodes('deadlock-list/deadlock/resource-list/keylock/owner-list') AS T(C)
  71. )
  72. SELECT
  73.         --A.OwnerID
  74.         A.SPid
  75.         ,is_Vitim = A.Victim
  76.         --,A.DeadlockGraph
  77.         ,A.SPName
  78.         ,A.Code
  79.         ,A.LockMode
  80.         ,A.StartTime
  81.         ,B.Indexname
  82.         ,B.KeylockObject
  83.         ,B.IndexLockMode
  84.         ,A.Inputbuf
  85.         ,A.Hostname
  86.         ,A.LoginName
  87.         ,A.Clientapp
  88.         ,A.Action
  89.         ,status
  90.         ,A.TransactionTime
  91. FROM deadlock AS A
  92.         LEFT JOIN keylock AS B
  93.         ON A.OwnerID = B.OwnerID
  94. ORDER BY A.RowNumber,A.Victim
复制代码

结果如下:


我们可以从结果中很明确的看到:
1.       spid=54号进程是DeadLock的牺牲品
2.       死锁时执行的语句是
spid=54
  1. UPDATE [dbo].[test_deadlock1] set [name] = @1  WHERE [id]=@2     
复制代码
spid=53
UPDATE [dbo].[test_deadlock2] set [name] = @1  WHERE [id]=@2     
3.      DeadLock时Lock的类型是X锁
4.      DeadLock是发生在主键上

说明
1.      7中保存Trace文件,你也可以将Trace信息保存到表中。然后将脚本中的第15行~第22行注释拿掉,然后注释掉第24行~第30行,也可以得到同样的信息
2.      DeadLock Graph的Trace文件中的textData其实是XML格式,我们的方法就是分析这个XML格式,只是大家需要了解每个节点,每个属性的含义。
3.      DeadLock Graph的XML文件也请参见下面的附件(也请将后缀名.sql修改为xml),以供大家参考
DeadlockGraph1.sql (3.75 KB, 下载次数: 47)
4.      解决DeadLock不是文本介绍的重点(当然通过这个方法查明原因后,解决问题是很简单的事情了)
5.      本例中解决DeadLock的方法是:按照相同的顺序访问表
6.      spid=54发生DeadLock时,会报告下面的错误
消息1205,级别13,状态51,第8 行
事务(进程ID 54)与另一个进程被死锁在锁资源上,并且已被选作死锁牺牲品。请重新运行该事务。

使用道具 举报

回复
论坛徽章:
14
迷宫蛋
日期:2012-03-13 09:50:292014年新春福章
日期:2014-02-18 16:44:08优秀写手
日期:2013-12-18 09:29:15迷宫蛋
日期:2012-06-13 15:28:34咸鸭蛋
日期:2012-06-11 16:11:11灰彻蛋
日期:2012-05-31 10:18:54双黄蛋
日期:2012-05-28 17:45:17茶鸡蛋
日期:2012-05-28 17:27:32蜘蛛蛋
日期:2012-05-28 16:54:09迷宫蛋
日期:2012-05-17 19:00:48
42#
 楼主| 发表于 2012-3-12 17:51 | 只看该作者
万恶啊~~不能上传.xml和.trc文件。。。。。。只能修改后缀名上传了~~得麻烦大家下载后自行修改后缀名了~~

使用道具 举报

回复
论坛徽章:
14
迷宫蛋
日期:2012-03-13 09:50:292014年新春福章
日期:2014-02-18 16:44:08优秀写手
日期:2013-12-18 09:29:15迷宫蛋
日期:2012-06-13 15:28:34咸鸭蛋
日期:2012-06-11 16:11:11灰彻蛋
日期:2012-05-31 10:18:54双黄蛋
日期:2012-05-28 17:45:17茶鸡蛋
日期:2012-05-28 17:27:32蜘蛛蛋
日期:2012-05-28 16:54:09迷宫蛋
日期:2012-05-17 19:00:48
43#
 楼主| 发表于 2012-3-12 17:52 | 只看该作者
本帖最后由 Cherish_j_wang 于 2012-3-12 17:53 编辑
hwtong 发表于 2012-3-8 20:40
好的 那样就更好了。希望能多多分享点东西给大家,让大家共同进步。
分享的多了,我是有奖励的哦

分享好多老了哟~~~~肚子都快要被掏空了,木有看到奖励呢?~~~

使用道具 举报

回复
论坛徽章:
14
迷宫蛋
日期:2012-03-13 09:50:292014年新春福章
日期:2014-02-18 16:44:08优秀写手
日期:2013-12-18 09:29:15迷宫蛋
日期:2012-06-13 15:28:34咸鸭蛋
日期:2012-06-11 16:11:11灰彻蛋
日期:2012-05-31 10:18:54双黄蛋
日期:2012-05-28 17:45:17茶鸡蛋
日期:2012-05-28 17:27:32蜘蛛蛋
日期:2012-05-28 16:54:09迷宫蛋
日期:2012-05-17 19:00:48
44#
 楼主| 发表于 2012-3-12 19:33 | 只看该作者
harrytwtc 发表于 2012-3-11 11:42
好物,收下了

谢谢您的光临

使用道具 举报

回复
论坛徽章:
582
Heart of PUB
日期:2012-06-09 19:13:29Heart of PUB
日期:2012-10-26 16:56:13Heart of PUB
日期:2012-12-05 13:26:39Heart of PUB
日期:2012-12-05 13:26:39Heart of PUB
日期:2012-12-05 13:26:39Heart of PUB
日期:2012-06-09 19:13:29红钻
日期:2012-06-02 09:42:42红钻
日期:2012-10-26 16:58:41红钻
日期:2012-10-26 16:58:41红钻
日期:2013-05-13 11:51:58
45#
发表于 2012-3-13 09:25 | 只看该作者
非常感谢LZ无私奉献,正在寻找相关的脚本.

使用道具 举报

回复
论坛徽章:
26
ITPUB伯乐
日期:2012-05-22 15:05:35喜羊羊
日期:2015-05-14 12:15:30美羊羊
日期:2015-07-02 22:22:59秀才
日期:2015-08-24 09:51:48天枰座
日期:2015-11-05 16:53:35双鱼座
日期:2015-12-05 19:22:56巨蟹座
日期:2015-12-20 18:46:10摩羯座
日期:2016-05-19 09:54:17ITPUB15周年纪念
日期:2016-10-13 13:15:34秀才
日期:2017-02-22 15:16:26
46#
发表于 2012-3-13 09:49 | 只看该作者
Cherish_j_wang 发表于 2012-3-12 17:52
分享好多老了哟~~~~肚子都快要被掏空了,木有看到奖励呢?~~~

马上奖励你
两个鸡蛋
666P

使用道具 举报

回复
论坛徽章:
14
迷宫蛋
日期:2012-03-13 09:50:292014年新春福章
日期:2014-02-18 16:44:08优秀写手
日期:2013-12-18 09:29:15迷宫蛋
日期:2012-06-13 15:28:34咸鸭蛋
日期:2012-06-11 16:11:11灰彻蛋
日期:2012-05-31 10:18:54双黄蛋
日期:2012-05-28 17:45:17茶鸡蛋
日期:2012-05-28 17:27:32蜘蛛蛋
日期:2012-05-28 16:54:09迷宫蛋
日期:2012-05-17 19:00:48
47#
 楼主| 发表于 2012-3-13 11:29 | 只看该作者
vsir01 发表于 2012-3-13 09:25
非常感谢LZ无私奉献,正在寻找相关的脚本.

看来是“好雨知时节,当春乃发生”啊~~

使用道具 举报

回复
论坛徽章:
14
迷宫蛋
日期:2012-03-13 09:50:292014年新春福章
日期:2014-02-18 16:44:08优秀写手
日期:2013-12-18 09:29:15迷宫蛋
日期:2012-06-13 15:28:34咸鸭蛋
日期:2012-06-11 16:11:11灰彻蛋
日期:2012-05-31 10:18:54双黄蛋
日期:2012-05-28 17:45:17茶鸡蛋
日期:2012-05-28 17:27:32蜘蛛蛋
日期:2012-05-28 16:54:09迷宫蛋
日期:2012-05-17 19:00:48
48#
 楼主| 发表于 2012-3-13 12:21 | 只看该作者
hwtong 发表于 2012-3-13 09:49
马上奖励你
两个鸡蛋
666P

接鸡蛋~接分~~谢主隆恩~

使用道具 举报

回复
论坛徽章:
0
49#
发表于 2012-3-13 12:36 | 只看该作者
学习了、、、

使用道具 举报

回复
论坛徽章:
14
迷宫蛋
日期:2012-03-13 09:50:292014年新春福章
日期:2014-02-18 16:44:08优秀写手
日期:2013-12-18 09:29:15迷宫蛋
日期:2012-06-13 15:28:34咸鸭蛋
日期:2012-06-11 16:11:11灰彻蛋
日期:2012-05-31 10:18:54双黄蛋
日期:2012-05-28 17:45:17茶鸡蛋
日期:2012-05-28 17:27:32蜘蛛蛋
日期:2012-05-28 16:54:09迷宫蛋
日期:2012-05-17 19:00:48
50#
 楼主| 发表于 2012-3-13 21:20 | 只看该作者
本帖最后由 Cherish_j_wang 于 2012-3-13 21:25 编辑

MSSQL DBA 精华总结
之MSSQL查看和清空存储过程缓存
背景
MSSQL DBA工作中经常会遇到的一个需求就是存储过程优化,那么在优化之前我们需要搞清楚下面的问题:
1.      存储过程中,哪个语句块(或者哪几个语句块)最消耗性能?
2.      这些语句块的执行详细的执行计划如何?
3.      如果某存储过程执行计划已经编译到缓存中,如何手动的删除?
其实在MSSQL中,上面提到的三个问题,我们都可以使用语句来实现。参见下面的脚本。

脚本
还是直接上测试脚本
ExecutionPlan_freeSP_Test.sql (2.56 KB, 下载次数: 58)

  1. --In SQL Server 2008
  2. USE test
  3. GO
  4. -----===建立测试表=====
  5. IF object_id('dbo.Test_SP_Cache','U') IS NOT NULL
  6.       DROP TABLE dbo.Test_SP_Cache
  7. GO
  8. CREATE TABLE dbo.Test_SP_Cache
  9. (
  10.       id int identity(1,1) PRIMARY KEY
  11.       ,name varchar(36)
  12. );

  13. -----===插入测试环境=====
  14. INSERT INTO dbo.Test_SP_Cache
  15. SELECT 'AA'
  16. UNION ALL
  17. SELECT 'BB'
  18. UNION ALL
  19. SELECT 'DD'
  20. UNION ALL
  21. SELECT 'DD'
  22. UNION ALL
  23. SELECT 'EE'
  24. UNION ALL
  25. SELECT 'EE'
  26. ;

  27. GO
  28. -----===建立测试存储过程=====
  29. IF object_id('dbo.UP_Test_SP_Cache','P') IS NOT NULL
  30.       DROP PROC dbo.UP_Test_SP_Cache
  31. GO
  32. CREATE PROC dbo.UP_Test_SP_Cache(
  33. @id int
  34. ,@name varchar(20)
  35. )
  36. AS
  37. BEGIN
  38.       SELECT name
  39.       FROM dbo.Test_SP_Cache WITH(NOLOCK)
  40.       WHERE id = @id
  41.       
  42.       update dbo.Test_SP_Cache
  43.       set name = NEWID()
  44.       where name = @name
  45. END;

  46. GO

  47. -----===查询应该无结果集=
  48. --因为存储过程还没有执行,所以还暂时没有执行计划
  49. SELECT *
  50. FROM sys.dm_exec_cached_plans AS cache
  51. CROSS APPLY sys.dm_exec_query_plan(cache.plan_handle)  AS pla
  52. CROSS APPLY sys.dm_exec_sql_text(cache.plan_handle) AS txt
  53. WHERE pla.objectid  = object_id('dbo.UP_Test_SP_Cache','P')
  54. and  txt.objectid  = object_id('dbo.UP_Test_SP_Cache','P')
  55. GO

  56. -----===执行存储过程=
  57. EXEC dbo.UP_Test_SP_Cache @id = 1,@name = 'DD';
  58. GO
  59. -----===查询应该有结果集=
  60. SELECT
  61.                 txt.text
  62.                 ,pla.query_plan
  63.                 ,database_name = DB_NAME()
  64.                 ,txt.objectid
  65.                 ,cache.objtype
  66.                 ,cache.size_in_bytes
  67. FROM sys.dm_exec_cached_plans AS cache
  68. CROSS APPLY sys.dm_exec_query_plan(cache.plan_handle)  AS pla
  69. CROSS APPLY sys.dm_exec_sql_text(cache.plan_handle) AS txt
  70. WHERE pla.objectid  = object_id('dbo.UP_Test_SP_Cache','P')
  71. and  txt.objectid  = object_id('dbo.UP_Test_SP_Cache','P')
  72. GO

  73. -----===清空某一存储过程的缓存=
  74. declare
  75.       @plan_id varbinary(64)
  76. ;

  77. SELECT @plan_id = cache.plan_handle
  78. FROM sys.dm_exec_cached_plans AS cache
  79. CROSS APPLY sys.dm_exec_query_plan(cache.plan_handle)  AS pla
  80. WHERE pla.objectid  = object_id('dbo.UP_Test_SP_Cache','P')

  81. DBCC FREEPROCCACHE (@plan_id);
  82. GO

  83. -----===缓存被清空查询应该无结果集=
  84. SELECT *
  85. FROM sys.dm_exec_cached_plans AS cache
  86. CROSS APPLY sys.dm_exec_query_plan(cache.plan_handle)  AS pla
  87. CROSS APPLY sys.dm_exec_sql_text(cache.plan_handle) AS txt
  88. WHERE pla.objectid  = object_id('dbo.UP_Test_SP_Cache','P')
  89. and  txt.objectid  = object_id('dbo.UP_Test_SP_Cache','P')
  90. GO

  91. -----===删除测试对象=
  92. IF object_id('dbo.Test_SP_Cache','U') IS NOT NULL
  93.       DROP TABLE dbo.Test_SP_Cache
  94. GO
  95. IF object_id('dbo.UP_Test_SP_Cache','P') IS NOT NULL
  96.       DROP PROC dbo.UP_Test_SP_Cache
  97. GO
复制代码
执行上面的测试语句,点击第三个结果集的query_plan
测试中存储过程的执行计划如下:
说明
1.      从存储过程的执行计划来看,第二个语句块性能消耗最为严重,为整个性能消耗的80%,所有这里是我们需要重点去优化的地方。

  1. update dbo.Test_SP_Cache
  2. set name = NEWID()
  3. where name = @name
复制代码

2.      清空存储过程执行计划的命令很简单DBCC FREEPROCCACHE (plan_handle),我们只需要找到这个Plan_handle即可。

  1. DBCC FREEPROCCACHE (@plan_id);
复制代码

3.      当然有的人可能说,我直接执行存储过程的每个语句块就好了嘛~~真的是这样吗?这种方法至少有三个坏处:
a)        产品环境中的MSSQL如果存在DML语句的存储过程是无法直接执行语句块的
b)        如果语句块中有对变量(变量常量或者表变量)的时候,每个语句块的执行变得不够现实
c)        每个语句块的执行显得既麻烦又繁琐

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表