클러스터 그룹 이름 확인

C:\> cluster group

 

통상적으로 영문일 경우 "Cluster Group" 한글일 경우 "클러스터 그룹" 으로 표시됨

 

 

 

쿼럼 리소스 이동

위 환경에서는  클러스터 그룹의 이름이 한글이므로 한글로 아래와 같이 입력

 

C:\>Cluster group "클러스터 그룹" /move:이동할서버(노드명)

 

 

 

* 클러스트 그룹이 영문일 경우 아래와 같이 이름만 변경 

C:\>Cluster group "Cluster Group" /move:이동할서버(노드명)

Windows 2012에서의 쿼럼리소스 이동

Windows 2012 Failover cluster의 경우 Core 리소스 이동이라는 메뉴로

 

쿼럼리소스 및 디스크 이동을 클러스터 관리자(GUI)에서 할 수 있음

/****** Object:  StoredProcedure [dbo].[sp_table_Spec]    Script Date: 04/25/2014 08:16:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCedure [dbo].[sp_table_Spec]
as
-- exec sp_table_Spec

Declare @i Int, @maxi Int
Declare @j Int, @maxj Int
Declare @sr int
Declare @Output varchar(4000)
Declare @last varchar(155), @current varchar(255), @typ varchar(255), @description varchar(4000), @tablename varchar(4000)

create Table #Tables  (id int identity(1, 1), Object_id int, Name varchar(155), Type varchar(20), [description] varchar(4000), [tablename] varchar(4000))
create Table #Columns (id int identity(1,1), Name varchar(155), Type Varchar(155), Nullable varchar(2), [description] varchar(4000))
create Table #Fk(id int identity(1,1), Name varchar(155), col Varchar(155), refObj varchar(155), refCol varchar(155))
create Table #Constraint(id int identity(1,1), Name varchar(155), col Varchar(155), definition varchar(1000))
create Table #Indexes(id int identity(1,1), Name varchar(155), Type Varchar(25), cols varchar(1000))

print '
<html xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns="http://www.w3.org/TR/REC-html40">

<head>
<meta http-equiv=Content-Type content="text/html; charset=ks_c_5601-1987">
<meta name=ProgId content=Excel.Sheet>
<meta name=Generator content="Microsoft Excel 14">
<link rel=File-List href="통합%20문서3.files/filelist.xml">
<style id="Styles">
<!--table
	{mso-displayed-decimal-separator:"\.";
	mso-displayed-thousand-separator:"\,";}
.font712580
	{color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;}
.xl1520912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:11.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl6320912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl6420912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:center;
	vertical-align:middle;
	border-top:none;
	border-right:.5pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:1.0pt solid windowtext;
	background:white;
	mso-pattern:black none;
	white-space:normal;}
.xl6520912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	border-top:none;
	border-right:.5pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:none;
	background:white;
	mso-pattern:black none;
	white-space:normal;}
.xl6620912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:center;
	vertical-align:middle;
	border-top:none;
	border-right:.5pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:none;
	background:white;
	mso-pattern:black none;
	white-space:normal;}
.xl6720912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	border-top:none;
	border-right:1.0pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:none;
	background:white;
	mso-pattern:black none;
	white-space:normal;}
.xl6820912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:center;
	vertical-align:middle;
	background:white;
	mso-pattern:black none;
	white-space:normal;}
.xl6920912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	background:white;
	mso-pattern:black none;
	white-space:normal;}
.xl7020912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	border-top:none;
	border-right:1.0pt solid windowtext;
	border-bottom:none;
	border-left:none;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl7120912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:700;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	border-top:none;
	border-right:none;
	border-bottom:none;
	border-left:1.0pt solid windowtext;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl7220912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:center;
	vertical-align:middle;
	border-top:none;
	border-right:.5pt solid windowtext;
	border-bottom:1.0pt solid windowtext;
	border-left:1.0pt solid windowtext;
	background:white;
	mso-pattern:black none;
	white-space:normal;}
.xl7320912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	border-top:none;
	border-right:.5pt solid windowtext;
	border-bottom:1.0pt solid windowtext;
	border-left:none;
	background:white;
	mso-pattern:black none;
	white-space:normal;}
.xl7420912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	border-top:none;
	border-right:1.0pt solid windowtext;
	border-bottom:1.0pt solid windowtext;
	border-left:none;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl7520912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:left;
	vertical-align:middle;
	border-top:1.0pt solid windowtext;
	border-right:none;
	border-bottom:.5pt solid windowtext;
	border-left:.5pt solid windowtext;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl7620912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:left;
	vertical-align:middle;
	border-top:1.0pt solid windowtext;
	border-right:none;
	border-bottom:.5pt solid windowtext;
	border-left:none;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl7720912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:left;
	vertical-align:middle;
	border-top:1.0pt solid windowtext;
	border-right:1.0pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:none;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl7820912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:left;
	vertical-align:middle;
	border-top:.5pt solid windowtext;
	border-right:none;
	border-bottom:1.0pt solid windowtext;
	border-left:.5pt solid windowtext;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl7920912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:left;
	vertical-align:middle;
	border-top:.5pt solid windowtext;
	border-right:none;
	border-bottom:1.0pt solid windowtext;
	border-left:none;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl8020912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:left;
	vertical-align:middle;
	border-top:.5pt solid windowtext;
	border-right:1.0pt solid windowtext;
	border-bottom:1.0pt solid windowtext;
	border-left:none;
	mso-background-source:auto;
	mso-pattern:auto;
	white-space:nowrap;}
.xl8120912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:700;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:center;
	vertical-align:middle;
	border-top:.5pt solid windowtext;
	border-right:.5pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:1.0pt solid windowtext;
	background:#D9D9D9;
	mso-pattern:black none;
	white-space:normal;}
.xl8220912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:700;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:center;
	vertical-align:middle;
	border-top:.5pt solid windowtext;
	border-right:.5pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:none;
	background:#D9D9D9;
	mso-pattern:black none;
	white-space:normal;}
.xl8320912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:700;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:center;
	vertical-align:middle;
	border-top:.5pt solid windowtext;
	border-right:1.0pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:none;
	background:#D9D9D9;
	mso-pattern:black none;
	white-space:normal;}
.xl8420912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	border-top:.5pt solid windowtext;
	border-right:1.0pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:none;
	background:#D9D9D9;
	mso-pattern:black none;
	white-space:nowrap;}
.xl8520912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:700;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:left;
	vertical-align:middle;
	border-top:1.0pt solid windowtext;
	border-right:.5pt solid windowtext;
	border-bottom:.5pt solid windowtext;
	border-left:1.0pt solid windowtext;
	background:#DAEEF3;
	mso-pattern:black none;
	white-space:normal;}
.xl8620912
	{padding-top:1px;
	padding-right:1px;
	padding-left:1px;
	mso-ignore:padding;
	color:black;
	font-size:9.0pt;
	font-weight:700;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-number-format:General;
	text-align:general;
	vertical-align:middle;
	border-top:none;
	border-right:.5pt solid windowtext;
	border-bottom:1.0pt solid windowtext;
	border-left:1.0pt solid windowtext;
	background:#DAEEF3;
	mso-pattern:black none;
	white-space:normal;}
ruby
	{ruby-align:left;}
rt
	{color:windowtext;
	font-size:8.0pt;
	font-weight:400;
	font-style:normal;
	text-decoration:none;
	font-family:"맑은 고딕", monospace;
	mso-font-charset:129;
	mso-char-type:none;}
-->
</style>
</head>

<body>
<div id="div" align=center x:publishsource="Excel">
'


set nocount on




--create Table #Tables  (id int identity(1, 1), Object_id int, Name varchar(155), Type varchar(20), [description] varchar(4000), [tablename] varchar(4000))

insert into #Tables (Object_id, Name, Type, [description],  [tablename])

Select o.object_id,  '[' + s.name + '].[' + o.name + ']', 
    case when type = 'V' then 'View' when type = 'U' then 'Table' end,  
    cast(p.value as varchar(4000)),
    CONVERT(varchar(4000),p.value)
    from sys.objects o 
       left outer join sys.schemas s on s.schema_id = o.schema_id 
       left outer join sys.extended_properties p on p.major_id = o.object_id and minor_id = 0 and p.name = 'MS_Description' and p.name = '테이블명'
--            where type in ('U', 'V') 
    where type in ('U')
--안쓰는 테이블 제외 
					and left(o.name, 2) in ('bi','co','ei','in','mk','mp','qc','sc')
--					and left(o.name, 2) in ('ac','fx')
--					and right(o.name, 5) not in ('excel','ackup') and right(o.name, 3) not in ('bak','web') 
--					and left(o.name, 2) not in ('tr','wy','as','ls','ds','dy','tb') and left(o.name, 5) not in ('cowrk','biacd')
    order by type, s.name, o.name
    
Set @maxi = @@rowcount


set @i = 1
While(@i <= @maxi)
begin
   --table header
   select @tablename = name, @description = [description] from #Tables where id = @i
      
   print '
<table border=0 cellpadding=0 cellspacing=0 width=838 style="border-collapse:
 collapse;table-layout:fixed;width:629pt">
 <col width=24 style="mso-width-source:userset;mso-width-alt:768;width:18pt">
 <col width=99 style="mso-width-source:userset;mso-width-alt:3168;width:74pt">
 <col width=194 style="mso-width-source:userset;mso-width-alt:6208;width:146pt">
 <col width=115 style="mso-width-source:userset;mso-width-alt:3680;width:86pt">
 <col width=118 style="mso-width-source:userset;mso-width-alt:3776;width:89pt">
 <col width=288 style="mso-width-source:userset;mso-width-alt:9216;width:216pt">
 <tr height=21 style="mso-height-source:userset;height:15.95pt">
  <td height=21 class=xl1520912 width=24 style="height:15.95pt;width:18pt"></td>
  <td class=xl6320912 width=99 style="width:74pt"></td>
  <td class=xl6320912 width=194 style="width:146pt"></td>
  <td class=xl6320912 width=115 style="width:86pt"></td>
  <td class=xl6320912 width=118 style="width:89pt"></td>
  <td class=xl6320912 width=288 style="width:216pt"></td>
 </tr>
 <tr height=21 style="mso-height-source:userset;height:15.95pt">
  <td height=21 class=xl1520912 style="height:15.95pt"></td>
  <td class=xl8520912 width=99 style="width:74pt">Table ID</td>
  <td colspan=4 class=xl7520912 style="border-right:1.0pt solid black;
  border-left:none">'+ isnull(@tablename, '') +'</td>
 </tr>
 <tr height=21 style="mso-height-source:userset;height:15.95pt">
  <td height=21 class=xl1520912 style="height:15.95pt"></td>
  <td class=xl8620912 width=99 style="width:74pt">Description</td>
  <td colspan=4 class=xl7820912 style="border-right:1.0pt solid black;
  border-left:none">' + isnull(@description, '') + '</td>
 </tr>
'
   --table columns
	truncate table #Columns 
   
  insert into #Columns  (Name, Type, Nullable, [description])
  --FOR 2005   
  Select c.name, 
           type_name(user_type_id) + (
           case when (type_name(user_type_id) = 'varchar' or type_name(user_type_id) = 'nvarchar' or type_name(user_type_id) ='char' or type_name(user_type_id) ='nchar')
              then '(' + cast(max_length as varchar) + ')' 
            when type_name(user_type_id) = 'decimal'  
                 then '(' + cast([precision] as varchar) + ',' + cast(scale as varchar)   + ')' 
           else ''
           end            
           ), 
           case when is_nullable = 1 then 'Y' else 'N'  end,
           cast(p.value as varchar(4000))
  from sys.columns c
        inner join #Tables t on t.object_id = c.object_id
        left outer join sys.extended_properties p on p.major_id = c.object_id and p.minor_id  = c.column_id and p.name = 'MS_Description' 
  where t.id = @i
  order by c.column_id
    
   Set @maxj =   @@rowcount
   set @j = 1
   
   
print '   
 <tr height=21 style="mso-height-source:userset;height:15.95pt">
  <td height=21 class=xl1520912 style="height:15.95pt"></td>
  <td class=xl7120912>Table Columns</td>
  <td class=xl6320912></td>
  <td class=xl6320912></td>
  <td class=xl6320912></td>
  <td class=xl7020912> </td>
 </tr>
 <tr height=21 style="mso-height-source:userset;height:15.95pt">
  <td height=21 class=xl1520912 style="height:15.95pt"></td>
  <td class=xl8120912 width=99 style="width:74pt">Sr.</td>
  <td class=xl8220912 width=194 style="width:146pt">Name</td>
  <td class=xl8220912 width=115 style="width:86pt">Datatype</td>
  <td class=xl8220912 width=118 style="width:89pt">Nullable</td>
  <td class=xl8320912 width=288 style="width:216pt">Description</td>
 </tr>
'

   While(@j <= @maxj)
   begin
      select	@Output = '
				 <tr height=21 style="mso-height-source:userset;height:15.95pt">
				  <td height=21 class=xl1520912 style="height:15.95pt"></td>
				  <td class=xl6420912 width=99 style="width:74pt">' + Cast((@j) as varchar) + '</td>
				  <td class=xl6520912 width=194 style="width:146pt">' + isnull(name,'')  + '</td>
				  <td class=xl6520912 width=115 style="width:86pt">' +  upper(isnull(Type,'')) + '</td>
				  <td class=xl6620912 width=118 style="width:89pt">' + isnull(Nullable,'N') + '</td>
				  <td class=xl6720912 width=288 style="width:216pt">' + isnull([description],'') + '</td>
				 </tr>'
         from #Columns  where id = @j      
      print    @Output    
      Set @j = @j + 1;
   end    
   --Indexes 
   truncate table #Indexes
   
   print ' <tr height=21 style="mso-height-source:userset;height:15.95pt">
  <td height=21 class=xl1520912 style="height:15.95pt"></td>
  <td class=xl7120912>Indexs</td>
  <td class=xl6320912></td>
  <td class=xl6320912></td>
  <td class=xl6320912></td>
  <td class=xl7020912> </td>
 </tr>'  
      insert into #Indexes  (Name, type, cols)
         select i.name, case when i.type = 0 then 'Heap' when i.type = 1 then 'Clustered' else 'Nonclustered' end,  col_name(i.object_id, c.column_id)
            from sys.indexes i 
               inner join sys.index_columns c on i.index_id = c.index_id and c.object_id = i.object_id 
               inner join #Tables t on t.object_id = i.object_id
            where t.id = @i
            order by i.name, c.column_id
  

   Set @maxj =   @@rowcount
   
   set @j = 1
   set @sr = 1
   if (@maxj >0)
   begin

      print ' 
 <tr height=21 style="mso-height-source:userset;height:15.95pt">
  <td height=21 class=xl1520912 style="height:15.95pt"></td>
  <td class=xl8120912 width=99 style="width:74pt">Sr.</td>
  <td class=xl8220912 width=194 style="width:146pt">Name</td>
  <td class=xl8220912 width=115 style="width:86pt">Type</td>
  <td class=xl8220912 width=118 style="width:89pt">Columns</td>
  <td class=xl8420912> </td>
 </tr>' 
      set @Output = ''
      set @last = ''
      set @current = ''
      While(@j <= @maxj)
      begin
         select @current = isnull(name,'') from #Indexes  where id = @j
                
         if @last <> @current  and @last <> ''
            begin   
            print
			'
			 <tr height=21 style="mso-height-source:userset;height:15.95pt">
			  <td height=21 class=xl1520912 style="height:15.95pt"></td>
			  <td class=xl6420912 width=99 style="width:74pt">' + Cast((@sr) as varchar) + '</td>
			  <td class=xl6520912 width=194 style="width:146pt">' + @last + '</td>
			  <td class=xl6520912 width=115 style="width:86pt">' + @typ + '</td>
			  <td class=xl6620912 width=118 style="width:89pt">' + @Output  + '</td>
			  <td class=xl6720912> </td>
			 </tr>'
            set @Output  = ''
            set @sr = @sr + 1
            end
         
            
         select @Output = @Output + cols + '<br />' , @typ = type
               from #Indexes  where id = @j
         
         set @last = @current    
         Set @j = @j + 1;
      end
      if @Output <> ''
            begin   
            print '
			  <tr height=21 style="mso-height-source:userset;height:15.95pt">
			  <td height=21 class=xl1520912 style="height:15.95pt"></td>
			  <td class=xl6420912 width=99 style="width:74pt">' + Cast((@sr) as varchar) + '</td>
			  <td class=xl6520912 width=194 style="width:146pt">' + @last + '</td>
			  <td class=xl6520912 width=115 style="width:86pt">' + @typ + '</td>
			  <td class=xl6620912 width=118 style="width:89pt">' + @Output  + '</td>
			  <td class=xl6720912> </td>
			 </tr>'
            end
   end

    Set @i = @i + 1;
    print '
    <tr height=21 style="mso-height-source:userset;height:15.95pt">
	  <td height=21 class=xl1520912 style="height:15.95pt"></td>
	  <td class=xl6820912 width=99 style="width:74pt" style="border-top:1.0pt solid black;"> </td>
	  <td class=xl6920912 width=194 style="width:146pt" style="border-top:1.0pt solid black;"> </td>
	  <td class=xl6920912 width=115 style="width:86pt" style="border-top:1.0pt solid black;"> </td>
	  <td class=xl6920912 width=118 style="width:89pt" style="border-top:1.0pt solid black;"> </td>
	  <td class=xl6320912 style="border-top:1.0pt solid black;"></td>
	 </tr>
	 <tr height=21 style="mso-height-source:userset;height:15.95pt">
	  <td height=21 class=xl1520912 style="height:15.95pt"></td>
	  <td class=xl6820912 width=99 style="width:74pt"> </td>
	  <td class=xl6920912 width=194 style="width:146pt"> </td>
	  <td class=xl6920912 width=115 style="width:86pt"> </td>
	  <td class=xl6920912 width=118 style="width:89pt"> </td>
	  <td class=xl6320912></td>
	 </tr>'
end

print'
</table>
</div>
</body>
</html>
'
drop table #Tables
drop table #Columns
drop table #FK
drop table #Constraint
drop table #Indexes 
set nocount off

'Database > Query' 카테고리의 다른 글

Find and Kill all the Blocked Process/Query  (0) 2020.09.22
오래된 커서  (0) 2020.09.11
sp_who3  (0) 2020.08.29
특정 문자열 포함하는 프로시저  (0) 2020.08.28
Full Scan, Index Scan Query  (0) 2020.08.28
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_who3')
DROP PROCEDURE sp_who3
GO
CREATE PROCEDURE sp_who3 @x NVARCHAR(128) = NULL 
WITH RECOMPILE
AS
/****************************************************************************************** 
   This is a current activity query used to identify what processes are currently running 
   on the processors.  Use to first view the current system load and to identify a session 
   of interest such as blocking, waiting and granted memory.  You should execute the query 
   several times to identify if a query is increasing it's I/O, CPU time or memory granted.
   
   *Revision History
   - 31-Jul-2011 (Rodrigo): Initial development
   - 12-Apr-2012 (Rodrigo): Enhanced sql_text, object_name outputs;
								  Added NOLOCK hints and RECOMPILE option;
								  Added BlkBy column;
								  Removed dead-code.
   - 03-Nov-2014 (Rodrigo): Added program_name and open_transaction_count	column
   - 10-Nov-2014 (Rodrigo): Added granted_memory_GB
   - 03-Nov-2015 (Rodrigo): Added parameters to show memory and cpu information
   - 12-Nov-2015 (Rodrigo): Added query to get IO info
   - 17-Nov-2015 (Rodrigo): Changed the logic and addedd new parameters
   - 18-Nov-2015 (Rodrigo): Added help content
*******************************************************************************************/
BEGIN
	SET NOCOUNT ON;
	IF @x IS NULL
		BEGIN
			SELECT r.session_id, se.host_name, se.login_name, Db_name(r.database_id) AS dbname, r.status, r.command,
				   CAST(((DATEDIFF(s,start_time,GetDate()))/3600) as varchar) + ' hour(s), '
					+ CAST((DATEDIFF(s,start_time,GetDate())%3600)/60 as varchar) + 'min, '
					+ CAST((DATEDIFF(s,start_time,GetDate())%60) as varchar) + ' sec' as running_time,
				   r.blocking_session_id AS BlkBy, r.open_transaction_count AS NoOfOpenTran, r.wait_type,
				   CAST(ROUND((r.granted_query_memory / 128.0)  / 1024,2) AS NUMERIC(10,2))AS granted_memory_GB,
				   object_name = OBJECT_SCHEMA_NAME(s.objectid,s.dbid) + '.' + OBJECT_NAME(s.objectid, s.dbid),
 				   program_name = se.program_name, p.query_plan AS query_plan,
				   sql_text = SUBSTRING	(s.text,r.statement_start_offset/2,
						(CASE WHEN r.statement_end_offset = -1 THEN LEN(CONVERT(nvarchar(MAX), s.text)) * 2
							ELSE r.statement_end_offset	END - r.statement_start_offset)/2),
					r.cpu_time,	start_time, percent_complete,		
					CAST((estimated_completion_time/3600000) as varchar) + ' hour(s), '
					+ CAST((estimated_completion_time %3600000)/60000 as varchar) + 'min, '
					+ CAST((estimated_completion_time %60000)/1000 as varchar) + ' sec' as est_time_to_go,
					dateadd(second,estimated_completion_time/1000, getdate()) as est_completion_time
			FROM   sys.dm_exec_requests r WITH (NOLOCK) 
			JOIN sys.dm_exec_sessions se WITH (NOLOCK)
				ON r.session_id = se.session_id 
			OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) s 
			OUTER APPLY sys.dm_exec_query_plan(r.plan_handle) p 
			WHERE  r.session_id <> @@SPID AND se.is_user_process = 1;
		END
	ELSE IF @x = '1'  OR @x = 'memory'
		BEGIN
			-- who is consuming the memory
			SELECT session_id, granted_memory_kb FROM sys.dm_exec_query_memory_grants WITH (NOLOCK) ORDER BY 1 DESC;
		END
	ELSE IF @x = '2'  OR @x = 'cpu'
		BEGIN
			-- who has cached plans that consumed the most cumulative CPU (top 10)
			SELECT TOP 10 DatabaseName = DB_Name(t.dbid),
							sql_text = SUBSTRING (t.text, qs.statement_start_offset/2,
										(CASE WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(nvarchar(MAX), t.text)) * 2
										ELSE qs.statement_end_offset END - qs.statement_start_offset)/2),
							ObjectName = OBJECT_SCHEMA_NAME(t.objectid,t.dbid) + '.' + OBJECT_NAME(t.objectid, t.dbid),
							qs.execution_count AS [Executions], qs.total_worker_time AS [Total CPU Time],
							qs.total_physical_reads AS [Disk Reads (worst reads)],	qs.total_elapsed_time AS [Duration], 
							qs.total_worker_time/qs.execution_count AS [Avg CPU Time],qs.plan_generation_num,
								qs.creation_time AS [Data Cached], qp.query_plan
			FROM sys.dm_exec_query_stats qs WITH(NOLOCK) 
			CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t
			CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp 
			ORDER BY DatabaseName, qs.total_worker_time DESC;
		END
	ELSE IF @x = '3'  OR @x = 'count'
		BEGIN
			-- who is connected and how many sessions it has 
			SELECT login_name, [program_name],No_of_Connections = COUNT(session_id)
			FROM sys.dm_exec_sessions WITH (NOLOCK)
			WHERE session_id > 50 GROUP BY login_name, [program_name] ORDER BY COUNT(session_id) DESC
		END
	ELSE IF @x = '4'  OR @x = 'idle'
		BEGIN
			-- who is idle that have open transactions
			SELECT s.session_id, login_name, login_time, host_name, host_process_id, status FROM sys.dm_exec_sessions AS s WITH (NOLOCK)
			WHERE EXISTS (SELECT * FROM sys.dm_tran_session_transactions AS t WHERE t.session_id = s.session_id)
			AND NOT EXISTS (SELECT * FROM sys.dm_exec_requests AS r WHERE r.session_id = s.session_id)
		END
	ELSE IF @x = '5' OR @x = 'tempdb'
		BEGIN
			-- who is running tasks that use tempdb (top 5)
			SELECT TOP 5 session_id, request_id,  user_objects_alloc_page_count + internal_objects_alloc_page_count as task_alloc
			FROM    tempdb.sys.dm_db_task_space_usage  WITH (NOLOCK)
			WHERE   session_id > 50 ORDER BY user_objects_alloc_page_count + internal_objects_alloc_page_count DESC
		END
	ELSE IF @x = '6' OR @x = 'block'
		BEGIN
			-- who is blocking
			SELECT DB_NAME(lok.resource_database_id) as db_name,lok.resource_description,lok.request_type,lok.request_status,lok.request_owner_type
			,wat.session_id as wait_session_id,wat.wait_duration_ms,wat.wait_type,wat.blocking_session_id
			FROM  sys.dm_tran_locks lok WITH (NOLOCK) JOIN sys.dm_os_waiting_tasks wat WITH (NOLOCK) ON lok.lock_owner_address = wat.resource_address 
		END
	ELSE IF @x = '0' OR @x = 'help'
		BEGIN
			DECLARE @text NVARCHAR(4000);
			DECLARE @NewLineChar AS CHAR(2) = CHAR(13) + CHAR(10);
			SET @text = N'Synopsis:' + @NewLineChar +
						N'Who is currently running on my system?'  + @NewLineChar +
						N'-------------------------------------------------------------------------------------------------------------------------------------'  + @NewLineChar +
						N'Description:'  + @NewLineChar +
						N'The first area to look at on a system running SQL Server is the utilization of hardware resources, the core of which are memory,' + @NewLineChar +
						N'storage, CPU and long blockings. Use sp_who3 to first view the current system load and to identify a session of interest.' + @NewLineChar +
						N'You should execute the query several times to identify which session id is most consuming teh system resources.' + @NewLineChar +
						N'-------------------------------------------------------------------------------------------------------------------------------------' + @NewLineChar +
						N'Parameters:'  + @NewLineChar +
						N'sp_who3 null				- who is active;' + @NewLineChar +
						N'sp_who3 1 or ''memory''  	- who is consuming the memory;' + @NewLineChar +
						N'sp_who3 2 or ''cpu''  	- who has cached plans that consumed the most cumulative CPU (top 10);'+ @NewLineChar +
						N'sp_who3 3 or ''count''  	- who is connected and how many sessions it has;'+ @NewLineChar +
						N'sp_who3 4 or ''idle'' 	- who is idle that has open transactions;'+ @NewLineChar +
						N'sp_who3 5 or ''tempdb'' 	- who is running tasks that use tempdb (top 5); and,'+ @NewLineChar +
						N'sp_who3 6 or ''block'' 	- who is blocking.'
			PRINT @text;
		END
END;
GO

 

'Database > Query' 카테고리의 다른 글

오래된 커서  (0) 2020.09.11
테이블 명세서  (0) 2020.08.29
특정 문자열 포함하는 프로시저  (0) 2020.08.28
Full Scan, Index Scan Query  (0) 2020.08.28
모든 인덱스 다시 리빌드, 통계 업데이트  (0) 2020.08.28

SQL Server 서비스가 시작될 때마다 새로운 로그 파일이 생성되게 됩니다. 즉, 서비스를 재시작하지 않으면 Error Log 파일 size 가 크게 늘어날 수 있습니다.

 

기본적으로 C:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\Log 폴더에 ERRORLOG ~ ERRORLOG.n(1~6) 까지의 파일이 생성되게 됩니다. 기본값으로 로그 파일 개수를 6개로 제한하였기 때문입니다. 이것은 SQL Server 를 6번 재시작 한다면 그 이전 로그는 사라진다는 것을 의미합니다.

 

 

필요에 따라 Error Log 파일 개수를 변경할 수 있습니다. 

 

SSMS - Management - SQL Server Logs - Configure - '재활용 이전의 오류 로그 파일 수 제한' 변경

 

 

아래 자료는 10개로 변경한 뒤 그 결과를 확인한 그림입니다.

 

 

 

 

T-SQL 로 확인해 봅니다. 

EXEC xp_enumerrorlogs

 

보관 #        날짜                         로그 파일 크기(바이트)

----------------------------------------------------------------

0               09/21/2009  10:47        1708

1               09/21/2009  10:47        1976

10              09/18/2009  11:13        311706

2               09/21/2009  10:47        1976

3               09/21/2009  10:47        1976

4               09/21/2009  10:47        1976

5               09/21/2009  10:47        1976

6               09/21/2009  10:47        1976

7               09/21/2009  10:47        11480

8               09/21/2009  10:25        11814

9               09/18/2009  11:58        13948

 

 

추가로 Registry NumErrorLogs 값을 변경할 수도 있습니다.

 

HKEY_LOCAL_MACHINE', N'Software\Microsoft\Microsoft SQL Server\MSSQL10.MSSQLServer\MSSQLServer', N'NumErrorLogs', REG_DWORD, 10

 

 



현재 설정된 값을 확인하기 위해서도 Reg 명령을 사용할 수 있습니다.

C:\>reg query "HKLM\Software\Microsoft\Microsoft SQL Server\MSSQL10.mssqlserver\mssqlserver" /v NumerrorLogs

 

 



 

그리고 또 하나!

SQL Server Error Log 파일의 size 가 늘어나면 SSMS 에서 불러오는 데 작은 고통을 느낄 수 있습니다. 서비스를 재시작 하지 않고 단지 로그 파일만 순환(CYCLE) 시키는 방법이 있으니 아래 T-SQL 을 참조하시면 되겠습니다.

 

EXEC sp_cycle_errorlog ;

 

 

[참고자료]

sp_cycle_errorlog(Transact-SQL)

http://msdn.microsoft.com/ko-kr/library/ms182512.aspx



출처: https://laigo.kr/356 [Lai Go's Blog]

'Database > SQL Server' 카테고리의 다른 글

SQL Server 인덱스 활성 / 비활성 하기  (0) 2020.08.31
쿼럼 리소스 이동  (0) 2020.08.29
악성 쿼리 찾아내기 - ReadTrace  (0) 2020.08.29
Master Key  (0) 2020.08.29
[DMV] 특정 프로시저의 실행계획이 바뀌었다?  (0) 2020.08.29

일반적으로 튜닝은 전체적으로 다음과 같은 단계들로 이루어진다.

  1. 무엇이 문제인지를 확인하고 현재 상태를 진단하여 튜닝의 기준선(Baseline)을 정의
  2. 병목이 발생하는 지점이 어디인지를 확인
  3. 확인된 병목을 해소할 방법을 모색
  4. 해소방법을 적용한 후 다시 성능을 측정하여 (1단계 기준선 대비) 실제로 성능이 향상되었는지를 확인


그래서 튜닝의 고수들은 가장 중요한 것이 "성능의 측정기준을 확인하는 것"이라고도 하지만, 나같은 하수에게는 아무래도 그것보다는 병목을 찾아내는 부분이 더 관심이 가게 마련이다. 6^^

보통 Profiler 를 사용하여 현재 DB에서 실행되는 SQL을 확인하고 악성 SQL을 확인하게 되는데... 이 작업을 하다 보면 다음과 같은 문제가 발생한다.

Type 1 : 분당 300건씩 실행되는 SQL
SELECT IP_ADDR FROM IP_TABLE WHERE SABUN = '29472' -- 실행시간 500ms

SELECT IP_ADDR FROM IP_TABLE WHERE SABUN = '38749' -- 실행시간 500ms
SELECT IP_ADDR FROM IP_TABLE WHERE SABUN = '32945' -- 실행시간 500ms
                              ...



Type 2 : 분당 1건씩 실행되는 SQL
SELECT SERIAL, IP_ADDR, START_DATE, END_DATE FROM IP_TABLE WHERE EMPNO NOT IN (SELECT EMPNO FROM INSATABLE WHERE STATUS = 'R') -- 실행시간 1000ms


위와 같은 두가지 유형의 SQL 중 어느것이 더 악성일까? 당연히 실행 빈도가 훨씬 높은 Type 1이다. 하지만 문제는 이걸 엄청나게 많은 SQL들이 섞여 있는 Profiler에서 육안으로 판단해내기가 쉽지 않다는 것이다. 따라서 악성 SQL을 확인할 때는 다음과 같이 SQL을 일반화해서 비교해야 한다.

Type 1 :
SELECT IP_ADDR FROM IP_TABLE WHERE SABUN = '##' -- 평균 실행시간 500ms, 총 실행시간 150000 ms

 

Type 2 :
SELECT SERIAL, IP_ADDR, START_DATE, END_DATE FROM IP_TABLE WHERE EMPNO NOT IN (SELECT EMPNO FROM INSATABLE WHERE STATUS = '##') -- 평균 실행시간 1000ms 실행시간 1000 ms


SQL Server 2000 에서는 수집한 SQL을 일반화하기 위해 Read80Trace 프로그램을 사용했었는데... SQL Server 2005에서 수집한 WorkLoad를 분석시키니.. 에러가 나고 제대로 실행이 되지 않았다.  
알고 보니 SQL Server 2005에서는 ReadTrace 라는 2005 버젼의 SQL 일반화 Tool 이 따로 제공되고 있었다. 
(프로그램 이름에서 80이 떨어진 걸 보니 이 프로그램은 추후 업그레이드될 SQL Server 버젼에서도 일반적으로 사용가능한 모양이다.)

이 프로그램을 사용하는 단계는 전체적으로 다음과 같다.

  1. RML 패키지  설치
  2. 부하(Workload) 수집
  3. 수집한 Workload 를 분석
  4. 분석 결과 확인

※ RML Utility 도움말에서는 SQLDiag.exe로 시스템 정보를 수집하는 내용이 있지만, 이것은 튜닝대상 서버의 환경을 분석하여 베이스 정보를 수집하기 위한 과정이고, Report 생성에 필요한 과정은 아니라고 도움말에 나와있다. ^^;


좀 더 자세히 살펴보면 다음과 같다.

Step 1. RML 패키지 설치
Workload 분석 툴인 ReadTrace와 Workload Replay 툴인 O'Stress로 이루어진 RML Utility (Replay Markup Language Utility)를 다운받아 설치한다. 가급적이면 분석 대상인 DB서버에 바로 설치하는 것이 여러 모로 편하다. 다음의 URL에서 다운로드할 수 있다.

 http://support.microsoft.com/kb/944837 

 

설치 중에 RML Reporter 프로그램을 설치하겠냐고 묻는데 함께 설치한다. 



Step 2. DB 에서 부하(Workload)를 수집
Profiler나 SQLDiag, SQL을 수집하는 스크립트(첨부) 등을 사용하여 현재 DB에서 수행되는 SQL (Workload)을 수집하고 trc 파일로 저장한다. 

Profiler를 사용하는 방법은... 쉽기는 한데 Workload 수집시에 서버 부하가 높고 내부적으로 ReadTrace가 요구하는 모든 이벤트를 수집해야 하는데 이 조건을 만족시키는 템플릿을 구하기가 어렵고 (내가 만들긴 귀찮고^^)... 모 등등 해서 아래의 SQL문으로 수집하는 것이 낫다. (스크립트 출처 : RML Utility 도움말)

 

 

 TraceCaptureDef.sql

 

해당 DB서버에서 SQL Server Management Studio로 열고 trc 파일 저장위치('InsertFileNameHere') 부분을 'D:\Test'와 같이 수정하여 실행해준다. trc 확장자는 자동으로 append되므로 붙일 필요가 없으며, 만약의 경우를 대비하여 OS가 설치된 파티션이나 mdf/ldf 파일이 존재하는 파티션과 다른 파티션에 저장하는 것이 좋다.

실행하면 아래와 같은 결과가 SELECT되는데 이 때 내가 실행시킨 수집(Trace) 세션의 ID (아래 그림에서는 "2")를 기억해놓도록 한다.

 



"메시지" 탭을 선택하면 이 수집(Trace) 작업을 중지시킬 때 뭐라고 입력해야 하는지를 친절하게 알려주고 있다. 

 




탐색기에서 아래와 같이 trc 파일에 Workload 결과가 쌓이는 것을 볼 수 있다. 처음에는 한동안 trc 파일 사이즈가 0KB로 남아있을 수 있는데, 새로고침을 누르면서 몇분간 기다리면 파일 사이즈가 늘어나는 것을 확인할 수 있다.

 




충분한 Workload가 수집되면 다음의 SQL을 실행하여 Trace를 중지시킨다.

 

exec sp_trace_setstatus 2, 0 -- stop trace job
exec sp_trace_setstatus 2, 2 -- delete and deallocate trace job



Step 3. 수집한 Workload 를 분석

이제 수집된 Workload를 분석하기 위해 ReadTrace 프로그램을 사용한다. 
ReadTrace 프로그램을 DB서버 Local에 설치했다면 이 작업도 당연히 DB서버 로컬에서 수행해야 한다.
ReadTrace.exe 는 커맨드 창에서 실행시켜야 하는 프로그램인데, 설치된 경로를 PATH 환경변수에 지정하기 위해 RML Utility에서 지원하는 RML Command창을 사용한다.

 


커맨드 창을 연 후 수집한 Workload 파일(trc 파일)이 있는 곳으로 이동하여 ReadTrace.exe를 실행시킨다.
(만약 RML 커맨드창이 아니라면 ReadTrace.exe 파일의 Full Path를 타이핑해주어야 한다.)

 


실행시키는 명령어는 ReadTrace /? 를 쳐보면 Usage를 볼 수 있으나 기본적으로는 아래와 같은 한가지 파라메터만 주면 된다.

 

D:\Temp\ReadTrace -ITraceFileName.trc

위와 같이 주면 기본적으로 분석 결과가 PerfAnalysis 라는 DB에 저장된다. 이 경우 여러번 분석하게 되면 이전 결과를 덮어쓰게 되므로 다음과 같이 DB 이름도 지정해줄 수 있다. (당연한 얘기지만... DB가 없으면 생성된다.)

D:\Temp\ReadTrace -ITraceFileName.trc -dPerfDB_20081218_1


Step 4. 분석 결과 확인

ReadTrace를 설치할 때 자동으로 함께 설치되는 RML Reporter 프로그램을 사용하여 분석된 결과를 Visual한 Report로 확인하고 악성 SQL을 찾아낸다. 최초 1번은 자동으로 실행되며 이후 레포트를 다시 보려면 다음과 같이 수동으로 Reporter 프로그램을 실행시키면 된다.

 


레포트의 첫 페이지는 아래와 같다. 
중앙의 큰 그래프는 Workload 수집 시간 중의 부하 변화를 그래프로 보여준다. 

 


여기서 부하를 어떤 기준으로 Grouping할지를 선택할 수 있는데, "Application Name"을 클릭할 경우 아래와 같이 Grouping할 Application을 선택할 수 있다. (한번 클릭할 때마다 탭이 새로 열린다.)

 


여기서 원하는 Application을 선택하면 아래와 같이 해당 Application이 실행시킨 SQL을 분석하여 보여준다.

 


위의 그래프를 보면 CPU Usage, Duration, Logical Read, Logical Write 등 다양한 기준 별로 사용율 Top 10 SQL을 보여주고 있다. 그래프에서는 1, 2, 3.. 이렇게 SQL의 번호만 표시되고 있는데, 스크롤 바를 조금만 내려보면 각 번호에 해당하는 SQL을 아래와 같이 보여준다.

 


위의 SQL중 하나를 클릭하면 아래와 같이 각 SQL에 대한 상세 정보를 볼 수 있다.

 




솔직히 난... 그래피컬하고 화려한 ReadTrace의 레포트보다 일목요연하고 가지고다니기 편한 Read80Trace의 html 레포트가 더 좋아보인다. (뭐 ReadTrace의 레포트도 Excel 내보내기를 지원하긴 한다.)

이렇게 악성SQL을 찾아내면... 그 다음은 개선만 하면 된다.
뭐, CPU사용율과 Logical Reads가 높은 SQL이라면 인덱스 쪽을 고려해볼 것이고, CPU사용율에 비해 Duration이 높은 경우라면 Blocking을 의심해볼 수 있을 것이다. 

A 노드에서 백업 받은 SMK가 B 노드에서 복원이 않되는 것은 자연 스러운 현상입니다.

B 노드에서 SMK를 읽기 위해서는 DAPI를 사용하는데, 이는 SQL Server의 자격 증명으로부터 파생된 키를 이용하게 됩니다.

즉 이로 인해 동일 서비스 계정이 아닐 경우에는 SMK의 복원 자체가 불가능합니다.

만약 강제로 복원을 시도하는 경우에는 SMK가 재 생성되는 것과 마찮가지로써, 크리덴셜을 이용하는 링크드 서버 및 기타 인증서를 이용한 암호화 구성에 문제가 발생할 수 있습니다.

[현상]

Veritas/Legato 클러스터에 Fail over 직후에 Linked Server 등이 연결이 안된다.

메세지 15466, 수준 16, 상태 2

[원인]

SMK 정보 변경

연결된 서버 암호, 인증서 또는 데이터베이스 마스터 키를 처음으로 암호화할 필요가 있을 때 자동으로 생성됨

SMK는 로컬 시스템 키 또는 Windows 데이터 보호 API(DAPI)를 사용하여 암호화된다. 이 API는 SQL Server 서비스 계정의 Windows 자격 증명으로부터 파생된 키를 사용한다.

서비스 마스터 키의 암호는 해당 키가 만들어진 서비스 계정이나 해당 서비스 계정의 Windows 자격 증명에 대한 액세스 권한이 있는 보안 주체에 의해서만 해독될 수 있다. 따라서 SQL Server 서비스를 실행 중인 Windows 계정을 변경하면 서비스 마스터 키의 암호 해독도 새 계정으로 활성화해야 한다.

[해결 방안]

1. 서비스를 Fail back 한다.

2. SMK를 백업 한다.

3. 두 노드 모두 SQL 서버의 시작 계정을 도메인 계정으로 변경 한다. (해당 작업은 동일 머신 상에서 진행 되어야 합니다.)

4. 연결 오류 발견 시 기존에 백업했던 SMK를 복원 한다.

[기타]

- 백업 및 복원

BACKUP SERVICE MASTER KEY TO FILE = 'c:\service_master_key' ENCRYPTION BY PASSWORD = 'password' 

RESTORE SERVICE MASTER KEY FROM FILE = 'c:\service_master_key' DECRYPTION BY PASSWORD = 'password' -- [FORCE]

- 재생성

ALTER SERVICE MASTER KEY REGENERATE

- 계정 변경

ALTER SERVICE MASTER KEY WITH OLD_ACCOUNT = 'old_service_account', OLD_PASSWORD = 'old_service_account_password'

http://blogs.msdn.com/lcris/archive/2005/07/08/437048.aspx

http://blogs.msdn.com/lcris/archive/2006/04/10/572678.aspx

http://blogs.msdn.com/lcris/archive/2005/09/30/475822.aspx

SMK에 대한 간단한 설명 : http://nexondbteam.tistory.com/35

SMK 생성 강제 적용 : http://support.microsoft.com/kb/914261

 

 

DBA가 관리하고 있는 DBMS에 특정 저장프로시저가 재컴파일 되면서 뜻하지 않게 원하지 않는 플랜 즉, 잘못된 플랜이 만들어 지면서 서버의 리소스를 소비하는 현상을 경험한 적이 있는 DBA 분들이 있을꺼에요. (없다고요?? 그럼 경험해 보셔야 해요. ^^;;;)

아무튼 우리 회사에서도 특정 저장프로시저가 재컴파일 되면서 INDEX SEEK를 해야 함에도 INDEX SCAN으로 플랜이 만들어지고 이로 인해서 서버의 리소스가 사용률이 약간 상승하는 일이 비일비재 해요. 이를 해결하기 위하여 여러가지 방법이 있겠지만, 전 왠지 이런 방법은 없을까? 라는 생각을 해봤어요.

 

재컴파일 참고 URL : http://support.microsoft.com/kb/243586

 

특정 프로시저 즉, 관심대상이 되는 프로시저의 플랜을 저장해 두었다가 현재 캐쉬되어 실행되고 있는 플랜의 물리적 연산자와 저장해둔 플랜의 물리적 연산자가 틀려지게 되면 알 수 있는 방법이 없을까?

그래서 만들고 있지요.

 

- 특정 프로시저들의 플랜을 저장한다. (물론 테이블을 만들어서)

- 현재 캐쉬되고 실행되는 플랜의 물리적 연산자와 저장된 플랜의 물리적 연산자와 비교 한다.

- 동일하면 일치라는 메시지를 출력한다.

- 동일하지 않다면 현재 캐쉬되어 실행되고 있는 플랜의 물리적 연산자 중 SCAN 이라는 물리적 연산자가 있으면 몇 개가 있고 그 물리적 연산자로 출력되는 예상 행수가 몇 개인지 출력한다.

 

 

[위 스크린샷이 저장해 놓은 플랜과 현재 캐쉬되어 실행되고 있는 플랜과 동일할 경우 출력되는 메시지 입니다.]

 

[위 스크린샷이 저장해 놓은 플랜과 현재 캐쉬되어 실행되고 있는 플랜이 동일 하지 않다면 SCAN 정보를 출력하는 메시지 입니다.]

 

두번째 스크린샷의 연산자 해석 방법은 해당 플랜의 SCAN의 포함되어 있는 물리적 연산자는 Clustered Index Scan 과 Table Scan 이 있으며, Clustered Index Scan 은 해당 플랜에서 총 3번이 있으며 그 3번의 평균 예상행수는 26만건 이며, Table Scan은 해당 플랜에 총 1번 있으며 그 1번의 예상행수는 45건 이라는 의미입니다. 해당 로직을 사용해 보고 공유할 만한 스크립트가 만들어 지면 올리겠습니다. 근데 멋있지 않나요?? 저만 멋있는건가요 ㅜ.ㅜ;;

 

 

 

 

 

특정 프로시저가 재 컴파일이 되면서 실행계획에 문제가 발생하면 CPU 사용률이 급격히 올라가기에 이 현상을 모니터링 하기 위해서 만들었고, 스크립트는 아래와 같습니다.

 

시작은 이랬습니다. DMV로 실행계획을 볼수 있고, 해당 실행계획은 XML로 되어 있으니 해당 XML에 있는 물리적 연산자를 몽땅 추출하여 내가 원하지 않는 연산자가 있는지 없는지를 알면 되지 않을까?

SELECT

        -- d.plan_handle ,

        OBJECT_NAME(b.objectid, b.dbid) [SP명] ,

        c.query_plan AS [프로시저 전체 실행계획]

        -- d.usecounts AS [실행계획이 만들어 진 이후로 사용된 횟수] ,

        -- b.text AS [프로시저 내용] ,

        --'EXEC ' + DB_NAME( b. dbid ) + '.DBO.sp_recompile ' + OBJECT_NAME ( b. objectid, b.dbid ) AS [ReCompile] ,

        --'DBCC FreeProcCache (' + sys. fn_varbintohexstr( d.plan_handle ) + ')' AS [실행계획 삭제]

FROM    sys.dm_exec_cached_plans AS d

        CROSS APPLY sys.dm_exec_sql_text(d.plan_handle) AS b

        CROSS APPLY sys.dm_exec_query_plan(d.plan_handle) AS c

WHERE   OBJECT_NAME(b.objectid, b.dbid) = 'usp_Disp_SelectCategorySumGoodsList_v3'

        AND b.text NOT LIKE '%sys.dm_exec_cached_plans%'

 

그럼 일단, 플랜을 저장하고 XML을 Query로 이용해서 물리연산자를 추출해 보자라고 생각했죠.

/*************************************************************************

*   쿼리 플랜을 저장한다.

*************************************************************************/

IF OBJECT_ID('tempdb..#AT_QueryPlanXml') IS NOT NULL

    BEGIN

        DROP TABLE #AT_QueryPlanXml

    END ;

 

-- 임시테이블을 만든다.

CREATE TABLE #AT_QueryPlanXml ( spName VARCHAR(500) ,

                                spPlan XML )

 

-- 특정 저장프로시저의 플랜을 저장한다.

-- 이왕 이면 주의대상 저장프로시저를 저장

INSERT  INTO #AT_QueryPlanXml

        ( spName ,

          spPlan )

SELECT

        -- d.plan_handle ,

        OBJECT_NAME(b.objectid, b.dbid) [SP명] ,

        c.query_plan AS [프로시저 전체 실행계획]

        -- d.usecounts AS [실행계획이 만들어 진 이후로 사용된 횟수] ,

        -- b.text AS [프로시저 내용] ,

        --'EXEC ' + DB_NAME( b. dbid ) + '.DBO.sp_recompile ' + OBJECT_NAME ( b. objectid, b.dbid ) AS [ReCompile] ,

        --'DBCC FreeProcCache (' + sys. fn_varbintohexstr( d.plan_handle ) + ')' AS [실행계획 삭제]

FROM    sys.dm_exec_cached_plans AS d

        CROSS APPLY sys.dm_exec_sql_text(d.plan_handle) AS b

        CROSS APPLY sys.dm_exec_query_plan(d.plan_handle) AS c

WHERE   OBJECT_NAME(b.objectid, b.dbid) = 'usp_Disp_SelectCategorySumGoodsList_v3'

        AND b.text NOT LIKE '%sys.dm_exec_cached_plans%'

 

 

/*************************************************************************

*   저장된 실행계획의 물리연산자를 추출한다.

*************************************************************************/

;WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS sp)

SELECT

        stmt.stmt_details.value( '@PhysicalOp', 'nvarchar(max)'),

        stmt.stmt_details.value( '@EstimateRows', 'nvarchar(max)')

FROM

        (

            SELECT  spPlan

            FROM    #AT_QueryPlanXml

        ) AS Result

CROSS APPLY spPlan.nodes('//sp:RelOp' ) AS stmt (stmt_details)

 

보시는봐와 같이 해당 프로시져 플랜의 연산자는 총 83개 중에 간간히 Clustered Index Scan 연산자를 이용하여 40만건이 넘는 행수를 읽고 있는게 보입니다. 그럼 Clustered Index Scan 이던 Table Scan 이던 해당 플랜 안에 Scan이 몇 개나 있고 그 예상행수는 얼마나 되는지를 판단하기 위하여 아래와 같은 최종 형태의 스크립트를 실행하시면 ...

USE DBA

GO

 

SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

 

/*--------------------------------------------------------------------------------------------

SP명 : DBA.FN_Query_PlanOp

작성자 : 이 승연

작성일 :

설명 : XML 안에 어떤 물리적연산이 있는지 확인

입력변수:

출력변수:

사용방법:

--------------------------------------------------------------------------------------------

작성자          작성일자         설명

--------------------------------------------------------------------------------------------

 

--------------------------------------------------------------------------------------------*/

CREATE FUNCTION DBO.FN_Query_PlanOp ( @QueryXML XML )

RETURNS VARCHAR(MAX)

AS

BEGIN

 

    DECLARE @Result VARCHAR(MAX) = '' ;

    DECLARE @TMP_Result VARCHAR(MAX) = '' ;

    DECLARE @Tmp_QueryXML TABLE ( ShowPlan XML ) ;

    DECLARE @Tmp_QueryXMLOp TABLE ( PhysicalOp VARCHAR(500) ,

                                    EstimateRows FLOAT ) ;

    --SELECT @Result = STR(@statement_start_offset) + ' : ' + CAST(@QueryXML AS VARCHAR(MAX))

 

    INSERT  INTO @Tmp_QueryXML

    VALUES  ( @QueryXML ) ;  

 

 

    WITH XMLNAMESPACES ( 'http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS sp)

    INSERT INTO @Tmp_QueryXMLOp

    SELECT

            stmt.stmt_details .value ( '@PhysicalOp' , 'nvarchar(max)' ) AS PhysicalOp ,

            stmt.stmt_details .value ( '@EstimateRows' , 'nvarchar(max)' ) AS EstimateRows

    FROM    (

                SELECT  *

                FROM    @Tmp_QueryXML

            ) AS Result

            CROSS APPLY ShowPlan. nodes( '//sp:RelOp' ) AS stmt ( stmt_details)

 

  

 

    SELECT  @TMP_Result = @TMP_Result + ', (' + PhysicalOp + '/'

            + CAST (COUNT(PhysicalOp) AS VARCHAR(100)) + '/'

            + REPLACE(CONVERT (VARCHAR, CONVERT (MONEY, AVG(EstimateRows)), 1),

                      '.00', '') + ')'

    FROM    @Tmp_QueryXMLOp

    WHERE   PhysicalOp LIKE '%SCAN%'

    GROUP BY PhysicalOp

 

    SELECT  @Result = CASE WHEN @TMP_Result = '' THEN '-'

                           ELSE RIGHT(@TMP_Result, LEN(@TMP_Result) - 1)

                      END

  

        -- Return the result of the function

    RETURN @Result

END

GO

 

 

 

-- 위 스칼라 함수 생성 후 아래와 같은 쿼리를 실행한다.

DECLARE @sp_Name VARCHAR(MAX) = '저장프로시저' ;

DECLARE @Query_Plan TABLE ( [plan_handle] [varbinary](64) NOT NULL ,

                            [SP명] [nvarchar](128) NULL ,

                            [프로시저 전체 실행계획] [xml] NULL ,

                            [실행계획이 만들어 진 이후로 사용된 횟수] [int] NOT NULL ,

                            [프로시저 내용] [nvarchar](MAX) NULL ,

                            [ReCompile] [nvarchar](279) NULL ,

                            [실행계획 삭제] [nvarchar](MAX) NULL ,

                            [statement_start_offset] [int] NOT NULL ,

                            [statement_end_offset] [int] NOT NULL ,

                            [ShowPlan] [xml] NULL ) ;

WITH    A AS ( SELECT   d.plan_handle ,

                        OBJECT_NAME(b.objectid, b.dbid) [SP명] ,

                        c.query_plan AS [프로시저 전체 실행계획] ,

                        d.usecounts AS [실행계획이 만들어 진 이후로 사용된 횟수] ,

                        b.text AS [프로시저 내용] ,

                        'EXEC ' + DB_NAME(b.dbid) + '.DBO.sp_recompile '

                        + OBJECT_NAME(b.objectid, b.dbid) AS [ReCompile] ,

                        'DBCC FreeProcCache ('

                        + sys.fn_varbintohexstr(d.plan_handle) + ')' AS [실행계획 삭제]

               FROM     sys.dm_exec_cached_plans AS d

                        CROSS APPLY sys.dm_exec_sql_text(d.plan_handle) AS b

                        CROSS APPLY sys.dm_exec_query_plan(d.plan_handle) AS c

               WHERE    OBJECT_NAME(b.objectid, b.dbid) = @sp_Name

                        AND b.text NOT LIKE '%sys.dm_exec_cached_plans%'

             ),

        B AS ( SELECT   A.plan_handle ,

                        A.[SP명] ,

                        A.[프로시저 전체 실행계획] ,

                        A.[실행계획이 만들어 진 이후로 사용된 횟수] ,

                        A.[프로시저 내용] ,

                        A.[ReCompile] ,

                        A.[실행계획 삭제] ,

                        qs.statement_start_offset ,

                        qs.statement_end_offset

               FROM     A AS A

                        INNER JOIN sys.dm_exec_query_stats AS qs

                            ON A.plan_handle = qs.plan_handle

             )

    INSERT  INTO @Query_Plan

            SELECT  B.* ,

                    CAST(qp.query_plan AS XML) AS [ShowPlan]

            FROM    B

                    CROSS APPLY sys.dm_exec_text_query_plan(B.plan_handle,

                                                            B.statement_start_offset,

                                                            B.statement_end_offset)

                    AS qp

 

 

SELECT  DBA.DBO.FN_Query_PlanOp(ShowPlan) AS [물리적연산] ,

        [SP명] ,

        [프로시저 전체 실행계획] ,

        [실행계획이 만들어 진 이후로 사용된 횟수] ,

        [프로시저 내용] ,

        [ReCompile] ,

        [실행계획 삭제] ,

        statement_start_offset ,

        statement_end_offset ,

        [ShowPlan]

FROM    @Query_Plan

 

해당 프로시저에 Clustered Index Scan 이 4건이 있으며 그 4건에 대한 평균 예상행수는 20만건이 있다고 출력을 해주고 있습니다. 그럼 이제 정상적인 플랜을 미리 저장해 두고 해당 스크립트로 현재 돌아가고 있는 플랜의 연산자를 추출하여 비교하면 어떤 연산자가 새로 생겼는지 기존에는 어떻게 돌고 있다가 재 컴파일 되면서 지금은 이렇게 돌고 있구나 라고 판단하실 수 있을 겁니다.

 

 

출처: https://ddoung2.tistory.com/359 [DDoung2]

'Database > SQL Server' 카테고리의 다른 글

악성 쿼리 찾아내기 - ReadTrace  (0) 2020.08.29
Master Key  (0) 2020.08.29
SQL Server2012 Checkpoint 제어  (0) 2020.08.29
sp_MSforeachdb  (0) 2020.08.29
dbforge Activity Monitor Permission  (0) 2020.08.29

-      Version : SQL Server 2012

   

SQL Server 데이터베이스 엔진은 자동으로 현재의 데이터베이스버퍼캐시에 있는 데이터를 디스크로 기록하는 CHECKPOINT 명령을 실행한다.

SQL Server 엔진은 성능상의 이유로 변경 내용이 있을 때마다메모리(버퍼캐시)에서 데이터베이스 페이지를 수정하며 이러한페이지를 디스크에 기록하지는 않는다. 대신 데이터베이스 엔진은 각 데이터베이스에서 정기적으로 CHECKPOINT를 실행 한다. CHECKPOINT는 현재 메모리내의 수정된 페이지(더티페이지)와 메모리의 트랜잭션 로그정보를 디스크에 쓰고 트랜잭션 로그에 대한 정보도 기록한다.

이 기능은 SQL Server의 예기치 않은 장애나 시스템 충돌로인하여 데이터베이스를 복구하는데 데이터의 안정성 및 시간을 절약할 수 있는 방법이 된다.

[CHECKPOINT]

http://msdn.microsoft.com/ko-kr/library/ms189573.aspx

http://msdn.microsoft.com/ko-kr/library/ms188748.aspx

   

SQL Server 2012의 TARGET_RECOVERY_TIME옵션과 recovery interval 옵션의 상호 작용

의 TARGET_RECOVERY_TIME

recovery interval

사용되는 검사점 유형

0

0

복구 간격이 1분인 자동 검사점

0

>0

복구 간격이 recovery interval 옵션 값 사용

>0

해당 사항 없음

복구 간격이 TARGET 옵션 값 사용.(초)

   

   

SSMS를 실행하여 다음 쿼리를 실행하면 해당 데이터베이스의 TARGET_RECOVERY_TIME 값을 확인 할 수 있다.

SELECT TARGET_RECOVERY_TIME_IN_SECONDS FROM SYS.DATABASES WHERE NAME = 'ADVENTUREWORKS2012'

   

 

      

   

   

SSMS의 UI로 확인도가능 하다. 다음과 같이 해당 데이터베이스에서 마우스 오른쪽을 클릭하여 [속성]을 선택 한다.

   

   

[데이터베이스 속성]창이나타나면 [옵션] 탭에서 [복구] – [대상 복구 시간(초)]에서확인 가능 하다.

   

   

스크립트를 이용하여 TARGET_RECOVERY_TIME 값을 변경하자. 실습에서는 120초 마다CHECKPOINT가 발생하도록 설정 하였다.

ALTER DATABASE AdventureWorks2012 SET TARGET_RECOVERY_TIME = 120 SECONDS

GO

   

SELECT TARGET_RECOVERY_TIME_IN_SECONDS FROM SYS.DATABASES WHERE NAME = 'ADVENTUREWORKS2012'

   

   

   

SSMS의 UI에서 변경도가능하다. 변경 방법은 위에서 확인한 [대상 복구 시간(초)]에서 변경하면 적용 된다.

   

   

[CHECKPOINT 제어의 장점]

-      특정 데이터베이스의 전체 복구 시간을 줄일 수 있다.

-      IO 비용을 고려하여 CHECKPOINT를 조절 할 수 있다.

   

[CHECKPOINT 제어의 단점]

-      매우 바쁜 OLTP 환경에서 성능 충돌이 발생할 수도 있다. 반드시 테스트 환경에서 검증하고 적용하자.

 

'Database > SQL Server' 카테고리의 다른 글

Master Key  (0) 2020.08.29
[DMV] 특정 프로시저의 실행계획이 바뀌었다?  (0) 2020.08.29
sp_MSforeachdb  (0) 2020.08.29
dbforge Activity Monitor Permission  (0) 2020.08.29
Deadlock  (0) 2020.08.29

sp_MSforeachdb, sp_MSforeachtable 프로시저 활용하기

 

  • Version : SQL Server 2008, 208R2, 2012

 

master 데이터베이스에 있는 sp_MSforeachtdb, sp_MSForeachtable 프로시저에 대해서 알아 보자. (필자도 업무용 쿼리를 분석하다 알게 되었다).

 

[sp_MSforeachdb]

sp_MSforeachdb 프로시저는 SQL Server 인스턴스 내에 있는 모든 데이터베이스의 이름을 반환하며 이 이름을 참조하여 지정된 반복문을 수행 한다.

 

아래 스크립트는 인스턴스내의 모든 데이터베이스의 helpfile 정보이다.

use master

go

 

exec sp_MSforeachdb 'use ? exec sp_helpfile'

 

 

 

아래 스크립트는 인스터턴스 내의 모든 데이터베이스 파일 정보를 반환 한다.

EXEC sp_MSforeachdb '

BEGIN

SELECT name,physical_name,state,size

FROM ?.sys.database_files

END'

 

 

 

다음 예제는 테이블 변수를 사용하여 테이블 변수에 데이터를 삽입 한다.

DECLARE @DatabasesSize TABLE

(

name VARCHAR(50),

physical_name VARCHAR(500),

state BIT,

size INT

)

INSERT INTO @DatabasesSize

EXEC sp_MSforeachdb 'IF ''?'' NOT IN (''tempDB'',''model'',''msdb'')

BEGIN

SELECT name,physical_name,state,size

FROM ?.sys.database_files

END'

 

select * from @DatabasesSize

 

 

 

다음 예제는 where 절에 use ? 를 사용한다.

EXEC sp_MSforeachdb 'IF ''?'' NOT IN (''tempDB'',''model'',''msdb'')

BEGIN

SELECT name,physical_name,state,size

FROM ?.sys.database_files

WHERE name LIKE ''?%'' -- Only Files starting with DB name

END'

 

 

 

[sp_MSforeachtable]

sp_MSforeachtable 프로시저는 현재 데이터베이스 내의 모든 테이블 이름을 반환하며 이 테이블이름을 참조하여 지정된 반복문을 수행 한다.

 

아래 스크립트는 해당 데이터베이스에 존재하는 모든 테이블의 row count를 테이블에 삽입하여 출력한다.

begin try

create table #rowcount (tablename varchar(128), rowcnt int)

end try begin catch end catch

 

exec sp_MSforeachtable

'insert into #rowcount select ''?'',

count(*) from ?'

select top 5 * from #rowcount

order by tablename

drop table #rowcount

 

 

위의 두 시스템 프로시저를 잘 활용하면 사용자 프로시저 생성시 코드를 간결하고 빠르게 개발 할 수 있을 듯 하다.

 

[참고자료]

'Database > SQL Server' 카테고리의 다른 글

[DMV] 특정 프로시저의 실행계획이 바뀌었다?  (0) 2020.08.29
SQL Server2012 Checkpoint 제어  (0) 2020.08.29
dbforge Activity Monitor Permission  (0) 2020.08.29
Deadlock  (0) 2020.08.29
메모리 / CPU 관련 성능 카운터  (0) 2020.08.29
  • CREATE DATABASE

  • ALTER ANY DATABASE

  • VIEW ANY DEFINITION

'Database > SQL Server' 카테고리의 다른 글

SQL Server2012 Checkpoint 제어  (0) 2020.08.29
sp_MSforeachdb  (0) 2020.08.29
Deadlock  (0) 2020.08.29
메모리 / CPU 관련 성능 카운터  (0) 2020.08.29
SQL Server 대기 통계 모니터링 : CPU 대기 해석  (0) 2020.08.29

+ Recent posts