Microsoft SQL Server Management Studio

 

1. 메뉴 > 쿼리 > InteliSense 사용

 

2. 메뉴 > 편집 > InteliSense > 로컬 캐시 새로고침

 

3. 도구 > 옵션 > 텍스트 편집기 > Transat-SQL > 일반

   > [체크] 멤버 목록 자동 표시

   > [체크] 매개 변수 정보

 

 

관련 내용 참고

http://blog.sqlauthority.com/2009/03/31/sql-server-2008-intellisense-does-not-work-enable-intellisense/

 

 

 

위 처럼 해도 안돼 다시 구글링 하여 보니
VS2010 SP1과 충돌이 돼어 안된다는 결론을 얻게 되었다.

 

현재는 64bit로 갈아탄 상태인데 그래서 안되는 거 일수도...

SQL Server 2008 r2에 대한 누적 업데이트 패키지 7 을 설치하라는 내용을 보게되었다.


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

에서 SQLServer2008R2_RTM_CU7_2507770_10_50_1777_x64 이 파일을 다운받는 중이다.(헐 300MB 세시간 걸린다)
(사실 뭘 받아야할지 판단이 안선다. 일단 해보고 안되면... 걍 써야겠다.)


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

오늘 MSSQL에 대한 정말 좋은 글을 보았다.

작년에 MSSQL교육에 나왔던 내용중 많은 부분이 담겨있어 많이 공감하며 읽어 내려갔다.

개발자로써 옆에 끼고 두고두고 명심해야 될 사항이 아닌가 하는 생각이 들어 옮겨놓는다.


출처 : debop.egloos.com/2652763

 

1. SELECT 절에 명시적으로 필요한 컬럼만을 지정하라.
SELECT * FROM TABLE_NAME 과 같이 모든 컬럼 정보를 가져와야 할 경우도 있지만, 대부분은 그렇지 않을 것이다.
"개발 시에 필요에 따라 컬럼 정보도 변경 될 수 있고, 조회할 컬럼이 바뀔 수도 있는데요?"
맞습니다. 그건 개발 시에 그렇죠. 그러니 최종 Release 할 때, 점검해서 필요한 컬럼만으로 줄여야 합니다.
이게 귀찮거든 TEXT, NTEXT, IMAGE 수형의 컬럼을 VARCHAR(MAX), VARBINARY(MAX)로 변경해라. 이중의 IO 작업을 줄일 수 있다.

 

2. WHERE 조건이 최적인지 확인하라
  우선 WHERE 조건이나 TABLE의 JOIN 에 쓰이는 컬럼이 인덱스로 잡혔는지 확인하라. 잡혀있어야 JOIN 성능이나 필터링이 좋다.
여러 필터링 중에 예상되는 결과 레코드 수가 적은 것부터 WHERE절에 써라 (이건 SQL Server 2000 부터는 SQL 실행계획이 알아서 해준다.)
다만, 여러번의 쿼리를 통해 임시테이블을 만들고, 조작해야 할 때는 SQL 작성자가 유의해서 작성해야 한다.

 

3. 컬럼 값의 변형을 WHERE절에 쓰는 경우를 최소화 해라.
  SELECT * FROM Customer WHERE Age + 1 > 20 보다는 WHERE Age > 19 이 빠르다.
물론 ISNULL 등도 마찮가지다.

 

4. Ctrl + L (SQLServer2008 기준) 를 이용해 실행계획을 확인해라.
  SQL 문의 실행계획을 보면, 처음에는 무슨 말인지 모를 수도 있다. 하지만 자꾸 보고, 쿼리 문을 변경하면서 실행계획이 변경되는 것을 보면서 익혀야 한다.

 

5. COUNT를 셀 것인가? exists 를 사용할 것인가?
  테이블에 조건에 맞는 레코드가 있음을 확인하는 방법은 count를 세는 방식과 exists 로 검사하는 방식이 있다.
  1. COUNT(*) 로 확인
      select @count = count(*) from Customers where name='aaaa'
      if @count > 0
      begin
  -- xxxxx
      end

  2. exists 사용
      if exists (select * from Customers where name='aaaa')
      begin
           --- xxxx
      end
   어떻게 좋을까? exists 가 좋다. count는 모든 레코드 중 관련된 것을 필터링 한 후 count 함수를 수행하지만, exists는 필터링 시 하나라도 레코드가 있음을 인지했을 때, 반환한다.
   테이블의 전체 레코드 수가 작을 때는 구별 안되지만, 많을 때는 exists 가 효과적이다.

 

6. count(컬럼명) 을 쓰지말고, count(*) 를 써라.
  count(컬럼명) 은 해당 컬럼 값이 NULL인 경우, count 수에 포함되지 않는다. (여러 집합함수가 다 그렇다). DB에서 NULL값은 오묘하니, 잘 이해해야 한다. DB에서 NULL은 산술 식에서 0을 의미하는 것이 아니라 N/A를 의미한다. 그러므로 비교도 않한다.

 

7. 커서를 최대한 자제하라.
  RDBMS 에서는 Set 방식을 사용하라 라는 말이 있다. 이 말은 레코드 단위로 addressing을 하는 커서 사용을 자제하라는 것이다.
커서 사용은 쿼리 문 실행을 느리가 하는 주범이다.
어쩔 수 없이 사용해야 할 경우도 있지만, 이 경우도 잘 생각하면, 여러 단계의 SET 방식을 사용해서 해결 할 수 도 있다.
타 시스템의 조직 정보를 재구성하는데 기존 커서 방식이 30초가 걸리던 것을 SET 방식으로 병경해서 3초 이하로 실행시간을 줄인 경우도 있다. 사실 더 줄일 수도 있다.

  또 하나는 임시 테이블을 사용하는 것인데, 이 때 주의할 점은 SQLServer tempdb의 SIZE 설정을 운영 시스템의 환경에 맞게 적절히 설정해야 한다. 기본적으로 data=3Mb(10%), log=1Mb(10%) 일 것이다. 이를 data=10~50Mb(10Mb), log=10Mb(10Mb) 로 변경해주면, 임시테이블 사용시 성능 향상을 가져 올 것이다. (참고 : Temp DB 최적화)
  더 좋은 방법은 테이블 변수를 사용하는 것입니다. 개인적으로 컬럼이 너무 많은 테이블 변수를 정의하는 게 싫어서...
꽁수로 필요한 최소한의 것만 테이블 변수에 정의하여 작업하고, 필요 시 실제 TABLE과 join을 수행하여, 결과 SET을 반환하도록 합니다.

 

8. VIEW 사용을 자제하라.
개발 편의상, 보안상 여러가지 이유로 VIEW는 참 좋은 개념이고, 사용할만한 가치가 있다.
다만 성능 상의 문제 때문에 자제하라는 것이다.
2번 WHERE 조건절 관련해서 언급했듯이, 결과 레코드가 가장 작게 가져오는 (HIT RATIO 가 높은) 문장이 먼저 실행되어야 하는데, VIEW를 먼저 가져오는 작업이 그 뒤에 실행되는 WHERE 절보다 더 많은 결과를 가져오게 하는 것이 대부분이므로, 성능에는 불리할 수 밖에 없다.
또한 여러 개의 테이블이 조인되는 경우 인덱스 사용에 제약이 많다. 물론 INDEXED VIEW가 있어서 어느정도 성능에는 효과가 있지만, 관련 테이블 변경 시 문제가 발생한다.

 

9. Table Hints 를 사용해라.
SELECT * FROM Customers with (nolock) 에서 nolock 같은 것이 table hint라 한다.
FASTFIRSTROW, IGNORE_CONSTRAINT, IGNORE_TRIGGERS, NOWAIT, PAGELOCK, TABLELOCK, ROWLOCK, UPDLOCK, XLOCK 등 여러가지가 있다.
일반적인 쿼리문에 적절한 Table Hint를 사용해서, 성능을 높힐 수 있다.

 

10. 왠만한 Data-Centric Product에서는 Procedure를 사용해라.

Procedure의 장점은 여러가지가 있지만, 몇가지만 나열하면
-. 데이터 무결성 시행
-. 복잡한 비지니스 규칙 표현
-. 캡슐화 가능
-. 네트웍 트래픽 감소 (긴 SQL 구문 축소)
-. 실행 계획 및 컴파일 캐시를 통한 실행 속도 향상
-. 보안 강화 (SQL Injection 방지) - 다른 방안도 있지만.

data-centric한 제품은 가능하면 Procedure를 제작해서 사용하는 것이 좋다. (개인적으로는 NHibernate를 사용하므로, procedure 쓸 일은 거의 없다.)
한가지 주의할 점은 procedure 이름의 접두사에 'sp_' 를 사용하지 말라는 것이다. 이 접두사는 SQLServer가 시스템 Procedure인 줄 알고, 거기부터 뒤진다. 대신 'usp_' 나 제품약어를 사용하는 것이 좋다.

 

11. 시스템 Procedure, 시스템 View를 잘 활용해라.

제품 자체는 아니지만 SQLServer 시스템의 정보를 활용하거나, 참조해야 할 때 sp_xxxx나 sysXXXX 등 master db에 있는 procedure나 view를 활용하는 것이 좋다.
특히 sql injection도 피하고, 컴파일 및 캐시도 지원하는 sp_executesql 를 잘 활용해라. 한마디로 동적 procedure라 할 수 있다.
다만 parameter가 있는 경우, 실제 값의 크기가 아닌 해당 parameter의 크기로 직접 설정하는 것이 더 성능이 좋다.

예 : 
      1. sp_executesql 'update name=''aaa'' where customers where name=@p0', '@p0 varchar(3)' @p0='bbb'
      2. sp_executesql 'update name=''aaa'' where customers where name=@p0', '@p0 varchar(5)' @p0='bbbbb'

위 두개의 쿼리 문은 똑 같지만 parameter 의 datatype이 달라, 전혀 다른 procedure로 컴파일된다.
가능하면 customer의 name 수형과 같은 수형을 parameter 수형으로 지정해 줘야 한다.


12. 기본 스키마 정보를 SQL 문장에 적어줘라.
select * from Customers 말고 select * from Northwind.dbo.Customers 를 쓰라는 말인데,
이는 sys, INFORMATION_SCHEMA 등 시스템용 schema와 구분짓기 위해서이고, 시스템이 객체 검색 시 효율적이기 때문이다.

 

13. SET NOCOUNT ON / OFF 를 사용해라.
Procedure의 경우 결과 셋으로 보내는 게 아니라, 내부적으로 중간 단계에서 사용하기 위해 조회를 수행하는 경우가 많다.
이 때 SET NOCOUNT ON 을 지정하고 수행해야, Client에게 조회 결과가 전달되지 않는다.
최종 결과만을 client에 보내기 위해서 SET NOCOUNT OFF 를 설정한 후, 최종 결과 조회 문을 실행해야한다.
이렇게 하는 것이 쓸데 없는 정보가 네트웍을 통해 반환되는 것을 방지한다.
많이 들어 봤겠지만 Network round-trip 이 성능에 가장 큰 적임을 잊지 마라.

 

14. 되도록 한꺼번에 SQL 문장을 실행하라.
Connection Pool 이 있어, Connection resource에 의한 성능 저하는 그리 없겠지만,
계속된 network round-trip은 성능에 많은 영향을 미친다. 되도록 한꺼번에 요청하고, 반환받아 round-trip을 최소화 해야 한다.


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

네이버 검색결과

http://blog.naver.com/ttltweety?Redirect=Log&logNo=60107917647

위의 링크에서 내용을 발췌해 복원에 시도하였지만 기존에 DB명이 무엇인지 데이터, 로그 파일명이 무엇인지 모르는 상태에서는

스크립트로 처리하는 부분에 어려움이 있었다.

bak파일이 있다면 아래 그림처럼 데이터베이스 복원에서 처리 하면 되긴하겠지만

왠지 스크립트로 처리 하고 싶은 욕구가 생겨서 시도 해 보았다.

 

 

 

 

 

다음은 처리한 스크립트의 예제이다.

 

 

--Check .bak FileInfo
RESTORE HEADERONLY FROM DISK = 'D:\MSSQL\DB_BACKUP\XXXXX.bak'   -- DB 백업파일이 있는 위치
RESTORE FILELISTONLY FROM DISK = 'D:\MSSQL\DB_BACKUP\XXXXX.bak'  -- DB 백업파일이 있는 위치
  

--Restore the Database
RESTORE DATABASE DB_NAME   -- 백업받은 DB의 명칭
FROM DISK= 'D:\MSSQL\DB_BACKUP\XXXXX.bak'   -- DB 백업파일이 있는 위치
WITH Move 'MDF_DATA' TO 'D:\MSSQL\DB_BACKUP\XXXXX.mdf',      -- 백업받은 DB의 MDF 데이터 파일명
 Move 'LDF_LOG' TO 'D:\MSSQL\DB_BACKUP\XXXX.ldf'   -- 백업받은 DB의 LDF 로그 파일명

 

 

 

DB복원에 앞서 백업할때 어떤 정보의 DB내용을 갖고 있는지 잘 확인해서 관리하는 것이 중요할거 같단 생각이 많이 들었다.

사실 오늘 이 작업도 다른 팀에서 백업을 받아와 복원한 상황이었던 터라 사전에 미리 말하지 못한 부분도 있고

사실 이전엔 백업, 복원 뭐 이런거 굳이 신경을 안써서 그랬을수도 있고 암튼 오늘 시원하게 복원할 수 있어 개운하다. ㅋㅋ


 


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

SELECT * FROM TABLE1 A WITH (NOLOCK)
            LEFT OUTER JOIN TABLE2 B WITH (INDEX = [INDEX_NAME], NOLOCK)
                                       ON A.[COL1] = B.[COL2]

 

-- 사실 MSSQL에서는 HINT사용을 그다지 추천하지 않는다고 합니다.(인터넷 여기저기 찾아본결과)

-- 하지만 하나의 테이블에 여러개의 HINT가 생성이 된 경우 의도하지 않는 결과값이 나온다고 판단된다면

-- 위와 같이 테이블에 HINT를 사용해 어느 인덱스를 사용할것인지 지정해 주는 것도 좋은 방법이 되지 않을까 생각이 됨.


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

------------------------------------------------------------------------------------------------------------------------------------------
-- MSSQL 모든테이블 통계 업데이트
------------------------------------------------------------------------------------------------------------------------------------------
DECLARE @SQL VARCHAR(5000)
SELECT @SQL = ''

DECLARE TAB_CUR CURSOR FOR
      SELECT A = 'UPDATE STATISTICS ' + TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
       WHERE TABLE_TYPE = 'BASE TABLE'
      
OPEN TAB_CUR
FETCH NEXT FROM TAB_CUR INTO @SQL
WHILE(@@FETCH_STATUS = 0)
BEGIN
   EXEC (@SQL)
   FETCH NEXT FROM TAB_CUR INTO @SQL
END      

CLOSE TAB_CUR
DEALLOCATE TAB_CUR


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

exec sp_lock

잠금 관련 정보를 보고합니다.

열 이름데이터 형식설명
spidsmallintSQL Server 프로세스 ID 번호입니다.
dbidsmallint잠금을 요청하는 데이터베이스 ID 번호입니다.
ObjIdint잠금을 요청하는 개체의 개체 ID 번호입니다.
IndIdsmallint인덱스 ID번호입니다.
Typenchar(4)잠금 유형입니다.

DB = 데이터베이스
FIL = 파일
IDX = 인덱스
PG = 페이지
KEY = 키
TAB = 테이블
EXT = 익스텐트
RID = 행 식별자

Resourcenchar(16)syslockinfo.restext의 값에 해당되는 잠금 리소스입니다.
Modenvarchar(8)잠금 요청자의 잠금 모드입니다. 이 잠금 모드는 허가된 모드, 변환 모드 또는 대기 모드를 표시합니다.
Statusint잠금 요청 상태입니다.

허가
대기
변환


exec sp_who {sp_id}

현재 Microsoft? SQL Server™ 사용자 및 프로세스에 관한 정보를 제공합니다. 유휴 상태가 아닌 프로세스만 반환하려면 반환되는 정보를 필터링하면 됩니다.

데이터 형식설명
spidsmallint시스템 프로세스 ID입니다.
ecidsmallint특정 SPID와 관련된 주어진 스레드의 실행 컨텍스트 ID입니다.

ECID = {0, 1, 2, 3, ...n}이며, 0은 항상 주 또는 부모 스레드를 의미하며 {1, 2, 3, ...n}는 하위 스레드를 의미합니다.

statusnchar(30)프로세스 상태입니다.
loginamenchar(128)특정 프로세스와 관련된 로그인 이름입니다.
hostnamenchar(128)각 프로세스의 호스트 또는 컴퓨터 이름입니다.
blkchar(5)프로세스를 차단하는 데 필요한 시스템 프로세스 ID입니다. 단, 존재하는 경우에 한합니다. 없는 경우, 이 열은 0이 됩니다.

고아 분산 트랜잭션이 주어진 spid 와 관련된 트랜잭션을 차단하면 이 열은 고아 트랜잭션을 차단하기 위해 '-2'를 반환합니다.

dbnamenchar(128)프로세스가 사용하는 데이터베이스입니다.
cmdnchar(16)Transact-SQL 문, SQL Server 내부 엔진 프로세스 등, 프로세스 실행에 필요한 SQL Server 명령입니다.


DBCC INPUTBUFFER( sp_id )

클라이언트에서 Microsoft? SQL Server™에 최종적으로 보낸 명령문을 표시합니다.

DBCC INPUTBUFFER는 다음과 같은 열이 있는 행 집합을 반환합니다.

열 이름데이터 형식설명
EventTypenvarchar(30)이벤트 유형(예: RPC, Language, NO Event)
ParametersInt0 = 텍스트
1- n = 매개 변수
EventInfonvarchar(255)RPC EventType의 경우, EventInfo에 프로시저 이름만 포함됩니다. Language 또는 No Event EventType의 경우, 이벤트의 첫 255자만 표시됩니다.

 


 

다음 내용은 MSDN에서 블록킹 해결하는 방법입니다.
 
블로킹은 잠금(Lock)을 기반으로 한 동시성을 지원하는 관계형 데이터베이스 관리 시스템(RDBMS)의 피할 수 없는 특성입니다. SQL Server에서 블로킹은 한 SPID가 특정 리소스에 대해 잠금(Lock)을 걸었는데 둘째 SPID가 동일한 리소스에 대해 충돌하는 잠금(Lock) 유형을 확보하려고 할 때 발생합니다. 일반적으로, 첫째 SPID가 리소스를 잠그는 시간 프레임은 매우 작습니다. 잠금(Lock)을 풀면 두번 째 연결은 자유롭게 리소스에서 자체 잠금(Lock)을 걸고 계속 처리할 수 있습니다. 이는 정상적인 동작이며 하루종일 시스템 성능에 인식할 수 있을만한 영향 없이 여러 번 일어날 수 있습니다. 

쿼리의 기간 및 트랜잭션 컨텍스트는 잠금(Lock)이 걸리는 시간을 나타내고 그 결과 다른 쿼리에 영향을 줄 수 있습니다. 쿼리가 트랜잭션에서 실행되지 않으면(그리고 잠금 참고(Lock HInts)가 사용되지 않으면) SELECT 문에 대한 잠금(Lock)은 쿼리 시간 대신 실제로 읽힐 때 리소스에만 걸립니다. INSERT, UPDATE 및 DELETE 문에 대해 잠금(Lock)은 데이터 일관성 및 필요한 경우 쿼리 롤백을 위해 쿼리의 시간 동안 걸립니다. 

트랜잭션에서 실행되는 쿼리에 대해 잠금(Lock)이 걸린 시간은 쿼리 유형, 트랜잭션 격리 수준(Isolation Level) 그리고 쿼리에서의 잠금 참고(Lock Hints) 사용 여부에 의해 결정됩니다. 잠금(Lock), 잠금 참고(Lock Hints) 참고 및 트랜잭션 격리 수준(Isolation Level)에 대한 설명은 SQL Server 온라인 설명서에 있는 다음 항목을 참조하십시오.
"Understanding Locking in SQL Server"
"Locking Architecture"
"Lock Compatibility"
"Locking Hints"
"Changing Default Locking Behavior in Oracle and SQL Server"
잠금(Lock) 및 블로킹이 시스템 성능을 저하시키는 지점까지 증가하는 경우 이는 일반적으로 다음과 같은 이유 중 하나에 의해서 입니다. 

SPID는 잠금(Lock)을 풀기 전에 확장된 시간 동안 리소스 집합에 대해 잠금(Lock)을 겁니다. 이러한 블로킹 유형은 시간이 지나면서 스스로 해결될 수 있지만 성능이 저하될 수 있습니다.
SPID는 리소스 집합에 대해 잠금(Lock)을 걸고 이를 절대로 풀지 않습니다. 이러한 블로킹 유형은 자체적으로 해결되지 않으며 영향을 받은 리소스에 무한정으로 액세스하지 못하게 합니다.
위의 첫 시나리오에서 블로킹 문제는 SPID가 잠금(Lock)을 풀면 자체적으로 해결됩니다. 그러나 서로 다른 SPID는 시간이 지남에 따라 이동 대상을 만들면서 여러 리소스를 블로킹할 수 있으므로 상황은 매우 달라집니다. 이러한 이유로 SQL Server Enterprise Manager(엔터프라이즈 관리자) 또는 개별 SQL 쿼리를 사용하여 상황을 해결하기 힘듭니다. 두 번째 상황의 결과로 진단하기 쉬운 일관성 있는 상태가 나옵니다.

블로킹 정보 수집

블로킹 문제 해결의 어려움을 해결하기 위해 데이터베이스 관리자는 지속적으로 SQL Server에서의 잠금(Lock) 및 블로킹 상태를 모니터하는 SQL 스크립트를 사용할 수 있습니다. 이러한 스크립트는 시간에 따른 특정 인스턴스의 스냅샷을 제공함으로 문제의 전체적인 그림을 만들어냅니다. SQL 스크립트로 블로킹을 모니터하는 방법에 대한 설명은 Microsoft 기술 자료에 있는 다음 문서를 참조하십시오. 본 문서에 있는 스크립트는 아래의 작업을 수행합니다. 가능하면 Enterprise Manager(엔터프라이즈 관리자) 또는 특정 SQL 쿼리에서 이 정보를 얻는 방법이 제공됩니다.
1.블로킹 체인 헤드에서 SPID를 식별합니다. 
위의 문서에 나온 스크립트를 사용하는 것 외에 다음과 같이 SQL Enterprise Manager(엔터프라이즈 관리자)를 사용하여 블로킹 체인의 헤드를 식별할 수도 있습니다. 

a.서버 그룹을 확장한 다음 서버를 확장합니다.
b.Management를 확장한 다음 Current Activity를 확장합니다.
c.Locks / Process ID를 확장합니다. 블로킹 정보와 함께 SPID는 세부 정보 창에 표시됩니다. 다른 것을 블로킹하는 SPID는 "(Blocking)"으로 나타납니다.
그러나 일부 tempdb 블로킹 문제는 사용자가 임시 테이블 작업을 사용하는 쿼리를 실행하지 못하도록 할 수 있으므로 때때로 Enterprise Manager(엔터프라이즈 관리자) 대신 쿼리를 사용해야 할 때가 있습니다. 직접 쿼리를 사용하면 이 문제를 피하는데 필요한 컨트롤을 제공합니다.
2.블로킹 SPID가 실행 중인 쿼리를 찾습니다. 
스크립트 메서드는 다음 쿼리를 사용하여 특정 SPID에서 실행된 명령을 결정합니다. 

DBCC INPUTBUFFER (<spid>)
또는 다음과 같이 SQL Enterprise Manager(엔터프라이즈 관리자)를 사용할 수 있습니다. 

a.서버 그룹을 확장한 다음 서버를 확장합니다.
b.Management를 확장한 다음 Current Activity를 확장합니다.
c.Process Info를 누릅니다. SPID는 세부 사항 창에 표시됩니다.
d.블로킹 SPID를 두 번 눌러 SPID가 실행한 최근 Transact-SQL 명령 일괄 처리를 봅니다.
3.블로킹 SPID가 걸고 있는 중인 블로킹 유형을 찾습니다. 
sp_loc 시스템 저장 프로시저(Stored Procedure)를 실행하여 이 정보를 결정할 수 있습니다. 또는 다음과 같이 Enterprise Manager(엔터프라이즈 관리자)를 사용할 수 있습니다. 

a.서버 그룹을 확장한 다음 서버를 확장합니다.
b.Management를 확장한 다음 Current Activity를 확장합니다.
c.Locks / Process ID를 확장합니다. 걸고 있는 잠금(Lock)에 대한 정보와 함께 SPID는 세부 사항 창에 표시됩니다.
4.블로킹 SPID의 트랜잭션 중첩 수준(Nesting Level) 및 프로세스 상태를 찾습니다. 
SPID의 트랜잭션 중첩 수준(Nesting Level)은 @@TRANCOUNT 전역 변수에서 사용할 수 있습니다. 그러나 다음과 같이 sysprocesses 테이블을 쿼리하여 SPID 외부에서 결정될 수 있습니다. 

SELECT open_tran FROM SYSPROCESSES WHERE SPID=<blocking SPID number>
go
반환된 값은 SPID의 @@TRANCOUNT 값입니다. 이는 블로킹 SPID의 트랜잭션 중첩 수준(Nesting Level)을 보여 주는데, 이는 잠금(Lock)을 건 이유를 설명할 수 있습니다. 예를 들어, 값이 0보다 크면 SPID는 트랜잭션 중간에 있습니다(트랜잭션 격리 수준에 따라 확보한 특정 잠금(Lock)을 걸 것으로 기대하는 경우). 

DBCC OPENTRAN 데이터베이스_이름을 사용하여 데이터베이스에 장기 개방 트랜잭션이 있는지 확인할 수도 있습니다.

SQL Server Profiler(프로필러) 추적(Trace) 정보 수집

위의 정보 외에 서버에서 이루어진 작업의 Profiler(프로필러) 추적(Trace)을 캡처하여 SQL Server에서의 블로킹 문제를 철저히 확인해야 합니다. SPID가 한 트랜잭션에서 여러 문을 실행하면 마지막 문만 DBCC INPUTBUFFER 출력에 나타납니다. 그러나 이전 명령 중 하나가 아직도 잠금(Lock)이 걸려 있는 원인이 될 수 있습니다. Profiler(프로필러) 추적(Trace)을 사용하면 현재 트랜잭션에서 SPID에 의해 실행된 모든 명령을 볼 수 있습니다. 다음 단계는 SQL Server Profiler(프로필러)를 설정하여 추적(Trace)을 캡처할 수 있도록 합니다.
1.SQL Server Profiler(프로필러)를 엽니다.
2.Tools 메뉴에서 Options를 누릅니다.
3.All Event Classes 및 All Data Columns 옵션을 선택해야 합니다.
4.OK를 누릅니다.
5.File 메뉴에서 New를 가리키고 Trace를 누릅니다.
6.General 탭에서 데이터를 캡처할 추적(Trace) 이름과 파일을 지정합니다.
7.Events 탭에서 다음과 같은 이벤트 유형을 추적(Trace)에 추가합니다. 

Error and WarningException이 이벤트는 예외가 발생했음을 나타냅니다. 
심각도가 25 이하인 예외는 오류가 SQL Server에서 클라이언트로 반환되었음을 나타냅니다. 심각도가 25인 예외는 내부 SQL Server 예외이며 아래의 설명대로 필터 아웃되어야 합니다.
Misc.Attention이 이벤트는 주의 신호가 발생하였음을 나타냅니다. 주의 신호의 일반 원인은 클라이언트 취소 또는 쿼리 시간 제한입니다.
SessionsConnect이 이벤트는 새 연결이 만들어졌음을 나타냅니다.
SessionsDisconnect이 이벤트는 클라이언트 연결이 끊어졌음을 나타냅니다.
SessionsExisting Connection이 이벤트는 SQL Profiler(프로필러) 추적(Trace)이 시작되는 시점에서 연결이 이루어졌음을 나타냅니다.
TSQLRPC:Starting이 이벤트는 원격 프로시저 호출(RPC)의 실행이 시작되었음을 나타냅니다.
TSQLSQL:BatchStarting이 이벤트는 Transact-SQL 일괄 처리의 실행이 시작되었음을 나타냅니다.
Stored ProceduresSP: StmtStarting이 이벤트는 저장 프로시저(Stored Procedure) 내에 있는 문이 실행을 시작하고 있음을 나타냅니다. 저장 프로시저(Stored Procedure) 이름은 해당 이벤트에 대한 텍스트의 시작 부분에 나타납니나.

이 외에도, 자세한 정보를 위해 다음 이벤트를 포함시킬 수 있습니다. 대량 생산 환경에서 실행하는 경우 위의 이벤트는 블로킹 문제를 해결하기에 충분하므로 이러한 이벤트 중 하나만 사용할 수 있습니다. 아래의 추가 이벤트를 포함하면 문제의 근원을 좀더 쉽게 빨리 결정할 수 있지만 시스템의 로드가 추가되고 추적 출력(Trace Output) 크기가 늘어납니다. 

Misc.Execution Plan이 이벤트는 실행된 Transact-SQL 문의 계획(Plan) 트리를 보여줍니다.
TransactionsDTCTransaction이 이벤트는 두 개 이상의 데이터베이스 또는 서버 간의 MS DTC(Microsoft Distributed Transaction Coordinator) 트랜잭션을 추적합니다.
TransactionsSQLTransaction이 이벤트는 SQL BEGIN, SAVE, COMMIT 및 ROLLBACK TRANSACTION 문을 추적(Trace)합니다.
TSQLRPC:Completed이 이벤트는 원격 프로시저 호출(RPC)의 실행이 완료되었음을 나타냅니다.
TSQLSQL:BatchCompleted이 이벤트는 Transact-SQL 일괄 처리의 실행이 완료되었음을 나타냅니다.
Stored ProceduresSP: StmtCompleted이 이벤트는 저장 프로시저(Stored Procedure) 내에 있는 문이 실행을 완료했음을 나타냅니다.
8.Data Columns 탭에 다음 열(Column)이 있는지 확인하십시오. Start Time, End Time, Connection ID, SPID, Event Class, Text, Integer Data, Binary Data, Application Name, NT User Name 및 SQL User Name. 위의 두번째 테이블에서 추가 이벤트를 포함하면 Duration, CPU, Reads 및 Writes 데이터 열(Column) 또한 포함시키십시오.
9.Filters 탭에서 SQL Server 내부 예외를 제외합니다. Trace Event Criteria 상자에서 Severity를 선택하고Maximum 상자에 24를 입력합니다. 그런 다음 OK를 누릅니다. 

SQL Server에서 클라이언트로 보내진 오류를 모니터하는데 대한 자세한 내용은 Microsoft 기술 자료에 있는 다음 문서를 참조하십시오.
199037 INF: Trapping Error Messages Sent to Clients from a SQL Server
Profiler(프로필러) 사용에 대한 내용은 SQL Server 온라인 설명서를 참조하십시오.

일반 블로킹 시나리오 식별 및 해결

위의 정보를 확인하여 대부분의 블로킹 문제의 원인을 파악할 수 있습니다. 본 문서의 나머지는 이 정보를 사용하여 일부 일반 블로킹 시나리오를 식별하고 해결하는 방법에 대한 설명입니다. 이 설명에서는 문서 Q251004(앞에서 참조됨)에 있는 블로킹 스크립트를 사용하여 블로킹 SPID에 대한 정보를 캡처하고 위에서 설명한 이벤트를 가지고 Profiler(프로필러) 추적(Trace)을 만들었다고 가정합니다.

블로킹 스크립트 출력 보기

sysprocesses 출력을 확인하여 블로킹 체인의 헤드를 파악합니다. 
블로킹 스크립트에 대해 고속 모드(Fast Mode)를 지정하지 않은 경우에는 스크립트 출력에는 다른 것을 블로킹하는 SPID를 나열하는 제목이 "SPIDs at head of blocking chains"인 부분이 있습니다. 

   SPIDs at the head of blocking chains
   spid
   ------
   9
   10
고속 옵션(Fast Option)을 지정하면 계속 sysprocesses 출력을 보고 블로킹 헤드를 파악할 수 있습니다. 다음은 간결한 sysprocesses 출력입니다. 

   spid   status                         blocked
    9     sleeping                       0
   10     sleeping                       0
   11     sleeping                       13
   12     sleeping                       10
   13     sleeping                       9
   14     sleeping                       12
이러한 경우 SPID 9와 10의 blocked 열(Column)에 0이 있음을 볼 수 있습니다. 이는 둘 다 블로킹되지 않았음을 의미하지만 기타 SPID에 대해 blocked 열(Column)에 나타납니다. 이는 SPID 9와 10이 별도의 블로킹 체인의 헤드에 있음을 나타냅니다.
블로킹 체인 헤드에 있는 SPID에 대한 정보에 대해 sysprocesses 출력을 확인합니다. 
다음 sysprocesses 필드를 평가하는 것은 중요합니다. 

Status 
이 열(Column)은 특정 SPID의 상태를 볼 수 있게 합니다. 일반적으로, sleeping 상태는 SPID가 실행을 완료하고 응용 프로그램에서 다른 쿼리 또는 일괄 처리를 제출할 때까지 기다리고 있음을 나타냅니다. runnable 상태는 SPID가 현재 쿼리를 처리하고 있음을 나타냅니다. 다음 표는 다양한 상태 값에 대한 간단한 설명을 제공합니다. 

BackgroundSPID가 백그라운드 작업을 수행 중입니다.
SleepingSPID가 현재 실행하고 있지 않습니다. 이는 일반적으로 SPID가 응용 프로그램에서 명령을 기다리고 있음을 나타냅니다.
RunnableSPID가 현재 실행 중입니다.
DormantSPID가 연결이 재설정된 일시 정지 상태에 있음을 나타냅니다.
RollbackSPID가 트랜잭션 롤백 중입니다.
DefwakeupSPID가 해제되고 있는 프로세스에 있는 리소스를 기다리고 있음을 나타냅니다. waitresource 필드는 문제의 리소스를 나타내야 합니다.
Spinloop프로세스가 SMP 시스템에서 동시성 제어에 사용되는 spinlock을 확보하려고 하면서 기다리고 있습니다.
Open_tran 
이 필드는 SPID의 트랜잭션 중첩 수준(Nesting Level)을 알려줍니다. 이 값이 0보다 크면 SPID는 열린 트랜잭션에 있고 트랜잭션의 문으로 확보한 잠금(Lock)을 걸고 있을 것입니다.
Lastwaittype, waittype 및 waittime 
lastwaittype 필드는 SPID의 마지막 또는 현재 대기 유형(waittype)을 알려줍니다. 이 필드는 SQL Server에서 새 필드이며 waittype 필드(예약된 내부 이진 열(Binary Column)임)의 문자열 표현입니다. waittype이 0x0000이면 SPID는 현재 아무것도 기다리고 있지 않으며 lastwaittype 값은 SPID에 있던 마지막 waittype을 나타냅니다. waittype이 0이 아니면 lastwaittype 값은 SPID의 현재 waittype을 나타냅니다. 

여러 lastwaittype 및 waittype 값에 대한 간단한 설명에 대해서는 Microsoft 기술 자료에 있는 다음 문서를 참조하십시오.
244455 INF: Definition of Sysprocesses Waittype and Lastwaittype Fields
waittime 값은 SPID가 진행 중인지를 파악할 때 유용할 수 있습니다. sysprocesses 테이블에 대한 쿼리에서 sysprocesses의 이전 쿼리의 waittime 값보다 작은 값을 waittime 열에 반환하면 이는 이전 잠금(Lock)이 확보되었다가 플렸으며 현재 새 잠금(Lock)을 기다리고 있음을 나타냅니다(waittime은 0이 아님을 가정). 이는 sysprocesses 출력 간에 waitresource를 비교하여 확인할 수 있습니다.
Waitresource 
이 필드는 SPID가 기다리고 있는 리소스를 나타냅니다. 다음 표는 일반 waitresource 형식과 그 의미를 나열합니다. 

테이블DatabaseID:ObjectIDTAB: 5:261575970 
이 경우 데이터베이스 ID 5는 pubs 예제 데이터베이스이고 개체 ID 261575970은 titles테이블입니다.
페이지DatabaseID:FileID:PageIDPAG: 5:1:104 
이 경우 데이터베이스 ID 5는 pubs이고 파일 ID 1은 기본 데이터 파일이며 페이지 104는 titles 테이블에 속하는 페이지입니다.
DatabaseID:ObjectID:IndexID(인덱스 키에 대한 해시(Hash) 값)키: 5:261575970:1 (5d0164fb1eac) 
이 경우 데이터베이스 ID 5는 pubs이고 개체 ID 261575970은 titles 테이블이며 인덱스 ID 1은 클러스터된 인덱스이고 해시(Hash) 값은 특정 행의 인덱스 키 값을 나타냅니다.
DatabaseID:FileID:PageID:Slot(row)RID: 5:1:104:3 
이 경우 데이터베이스 ID 5는 pubs이고 파일 ID 1은 기본 데이터 파일이며 페이지 104는 titles 테이블에 속하는 페이지이고 슬롯 3은 페이지에서 행의 위치를 나타냅니다.
컴파일DatabaseID:ObjectIDTAB: 5:834102012 [[COMPILE]] 
이 경우 데이터베이스 ID 5는 pubs이지만 개체 ID 834102012는 저장 프로시저(Stored Procedure)입니다. 이는 SPID가 저장 프로시저(Stored Procedure)에 대한 계획(Plan)이 컴파일되기를 기다리고 있음을 나타냅니다.
기타 열(Column) 
나머지 sysprocesses 열(Column)은 문제의 근본에 대한 통찰력도 제공합니다. 그 유용성은 문제의 상황에 따라 달라집니다. 예를 들어, SPID에서 제출한 마지막 일괄 처리가 (last_batch)일 때 특정 네트워크 라이브러리(net_library)에서 특정 클라이언트(hostname)로부터만 발생하는지 파악할 수 있습니다. 모든 sysprocesses 열에 대한 간단한 설명에 대해서는 SQL Server 7.0 온라인 설명서에 있는 "sysprocesses(T-SQL)" 항목을 참조하십시오. 

참고: SUID 열(Column)은 역방향 호환성을 위해서만 포함된 열(Column)에서 파생되므로 블로킹 스크립트 출력에 포함되지 않습니다. 이는 SQL Server에서 내부적으로 사용되지 않으며 이를 쿼리하면 성능이 저하될 수 있으므로(파생되었으므로) 포함되지 않습니다.
DBCC INPUTBUFFER 출력을 확인합니다. 

블로킹 체인의 헤드에 있는 SPID에 대해 또는 0이 아닌 waittype을 가지고 블로킹 스크립트는 DBCC INPUTBUFFER를 실행하여 그 SPID에 대한 현재 쿼리를 결정합니다. 

   DBCC INPUTBUFFER FOR SPID 9
   EventType      Parameters EventInfo
   -------------- ---------- --------------------------------------------
   Language Event 0          update titles set title = title
대부분의 경우 이 쿼리는 다른 사용자를 블로킹하는 잠금(Lock)을 걸 수 있습니다 . 그러나 트랜잭션에 SPID가 있으면 잠금(Lock)은 현재 쿼리가 아닌 이전에 실행된 쿼리에서 얻을 수 있습니다. 그러므로 inputbuffer만 아니라 SPID에 대해 Profiler(프로필러) 출력도 봐야 합니다. 

참고: 블로킹 스크립트는 여러 단계로 구성되므로 SPID는 블로킹 체인의 헤드에 첫 섹션으로 나타날 수 있지만 DBCC INPUTBUFFER 쿼리가 실행될 때 이는 더 이상 블로킹되지 않고 INPUTBUFFER는 캡처되지 않습니다. 이는 그 SPID에 대해 블로킹이 스스로를 해결하고 있음을 나타내는데, 이는 문제가 될 수도 있고 그렇지 않을 수도 있습니다. 이 때 블로킹 스크립트의 고속(Fast) 버전을 사용하여 inputbuffer가 지워지기 전에 이를 캡처하거나(비록 보장할 수는 없어도) 그 시간 프레임에서 Profiler(프로필러) 데이터를 보고 SPID가 실행하는 쿼리를 결정할 수 있습니다.
DBCC PSS 출력을 확인합니다. 
블로킹 체인의 헤드에 있는 모든 SPID에 대해 DBCC PSS 명령을 실행합니다. PSS는 프로세스 상태 구조로 특정 SPID의 상태에 대한 정보가 들어 있습니다. 블로킹 시나리오의 가장 큰 관심 필드는 ec_stat 필드입니다. 다음은 ec_stat 필드의 일반 값입니다. 

0x2프로세스가 종료되었습니다. 이는 SPID가 중단되었음을 나타냅니다.
0x40프로세스는 쿼리 시간 제한 또는 취소에 의해 클라이언트로부터 주의 신호를 받았습니다. 이는 현재 활성 쿼리가 중단되고 있기는 하지만 0x2에서와 같이 전체 SPID는 아님을 나타냅니다.
0x80프로세스가 여러 데이터베이스 트랜잭션에 관련되어 있습니다.
0x200프로세스가 서버 간 원격 프로시저 호출(RPC)를 수행하고 있습니다.
0x400사용자가 NOLOCK 참고(Hint)가 있는 쿼리를 수행하고 있습니다.
0x800프로세스가 롤백 중이며 교착 상태 대상으로 선택될 수 없습니다.
0x2000프로세스가 현재 중단되고 있습니다.


참고: 고속 모드(Fast Mode)에서 블로킹 스크립트는 DBCC PSS 명령을 실행하지 않습니다. 이 정보의 대부분은 Profiler(프로필러) 추적(Trace) 데이터를 보고 결정될 수 있습니다. 추적(Trace) 파일에서 ATTENTION 신호와 예외를 볼 수 있습니다. 예를 들어, 프로세스가 교착 상태에 있으면 교착 상태가 발생할 때 클라이언트에 반환되는 오류인 정수 데이터 열(Column) 값이 1205인 예외 이벤트를 볼 수 있습니다. ec_stat 값은 0이 아닐 때 좀더 자세히 살펴 보기 위한 신호로 유용하게 사용됩니다. SPID가 "정상" 상태에 있지 않으면 경고합니다. 위의 표와 Profiler(프로필러) 추적(Trace) 정보에서 이에 대한 원인과 그 진행 방법을 파악할 수 있습니다.

Profiler(프로필러) 데이터 보기

블로킹 문제 해결에서 Profiler(프로필러) 데이터를 효율적으로 보는 것이 매우 중요합니다. 가장 중요한 사실은 캡처한 모든 것을 볼 필요 없이 선택적으로 볼 수 있다는 것입니다. Profiler(프로필러)는 캡처된 데이터를 효과적으로 볼 수 있도록 기능을 제공합니다. Properties 대화 상자(File 메뉴에서 Properties 누름)에서 Profiler(프로필러)를 사용하여 데이터 열(Column) 또는 이벤트를 제거하고 데이터 열(Column)을 그룹화(정렬)하며 필터를 적용하여 표시되는 데이터를 제한할 수 있습니다. 전체 추적(Trace)을 검색하거나 Edit 메뉴에서 Find를 눌러 특정 값에 대해 특정 열(Column)만 검색할 수도 있습니다. Profiler(프로필러) 데이터를 SQL Server 테이블(File 메뉴에서 Save As를 가리킨 다음 Table을 누름)에 저장하고 이에 대해 SQL 쿼리를 실행할 수도 있습니다. 

이전에 저장한 추적(Trace) 파일에만 필터링을 수행해야 합니다 . 활성화된 추적(Trace)에서 이러한 단계를 수행하면 추적(Trace)을 시작한 후에 캡처한 데이터는 손실될 우려가 있습니다. 먼저 활성화된 추적(Trace)을 파일 또는 테이블에 File 메뉴에서 Save As를 눌러 저장한 다음 진행하기 전에 이를 File 메뉴에서 Open을 눌러 다시 엽니다. 저장된 추적(Trace) 파일에서 작업할 때는 필터링이 필터된 데이터를 영구적으로 제거하지 않으며 단지 모든 데이터를 표시하지 않을 뿐입니다. 특히 중점을 두는 검색에 필요한 이벤트와 데이터 열(Column)을 추가하거나 삭제할 수 있습니다. 

찾아야 할 내용:
현재 트랜잭션에서 블로킹 체인의 헤드에 있는 SPID에서 어떤 명령을 실행했습니까? 
블로킹 체인의 헤드에 있는 특정 SPID의 추적(Trace) 데이터를 필터합니다(File 메뉴에서 Properties를 누른 다음 Filters 탭에서 SPID 값을 지정함). 그러면 다른 SPID를 블로킹하기 전에 실행한 명령을 확인할 수 있습니다. 트랜잭션 이벤트를 포함하면 트랜잭션이 언제 시작되었는지를 쉽게 식별할 수 있습니다. 그렇지 않으면 Text 열에서 BEGIN, SAVE, COMMIT 또는 ROLLBACK TRANSACTION 작업을 검색할 수 있습니다. sysprocesses 테이블에서 open_tran 값을 사용하여 모든 트랜잭션 이벤트를 잡아야 합니다. 실행된 명령과 트랜잭션 컨텍스트를 알면 SPID에서 잠금(Lock)을 걸고 있는 이유를 파악할 수 있습니다. 

이벤트와 데이터 열(Column)을 제거할 수 있다는 것을 유의하십시오. 시작 및 완료 이벤트를 둘 다 보는 대신 하나를 선택하십시오. 블로킹 SPID가 저장 프로시저(Stored Procedure)가 아니면 SP:Starting 또는 SP:Completed 이벤트를 제거합니다. SQLBatch 및 RPC 이벤트는 프로시저 호출을 보여 줍니다. SP 이벤트의 세부 사항 수준을 봐야 하는 경우에만 이를 보십시오.
블로킹 체인의 헤드에 있는 SPID의 쿼리 기간은 어느 정도입니까? 
위의 완료된 이벤트를 포함시킬 경우 Duration 열은 쿼리 실행 시간을 보여 줍니다. 이를 사용하면 블로킹을 일으키는 장기간 실행되는 쿼리를 식별할 수 있습니다. 쿼리의 수행 속도가 느린 이유를 파악하려면 CPURead 및 Writes 열(Column)뿐만 아니라 Execution Plan 이벤트도 보십시오.

일반 블로킹 시나리오 분류

다음 표는 일반 증상과 그에 해당되는 원인을 나타냅니다. Scenario 열에 표시된 번호는 아래 문서의 "일반 블로킹 시나리오 및 해결책" 절에 있는 번호에 해당합니다. Waittype , Open_Tran 및 Status 열(Column)은 sysprocesses 정보입니다. Resolves? 열(Column)은 블로킹이 자체적으로 해결되었는지 여부를 나타냅니다. 

10이 아님>= 0runnable예, 쿼리가 완료할 때입니다.Physical_IO, CPU 및/또는 Memusage 열(Column)은 시간이 지나면서 증가합니다. 쿼리의 기간은 완료될 때 높아집니다.
20x0000>0sleeping아니오, 그러나 SPID는 중단됩니다.이 SPID에 대해 Profiler(프로필러) 추적(Trace)에서 주의 신호를 볼 수 있는데 이는 쿼리 시간 제한 또는 취소가 발생하였음을 나타냅니다.
30x0000>= 0runnable아니오. 클라이언트가 모든 행을 반입하거나 연결을 닫을 때까지 해결되지 않습니다. SPID는 중단될 수 있습니다. 그러나 중단하는데 30초 정도 걸립니다.open_tran = 0이고 SPID가 트랜잭션 격리 수준(Isolation Level)이 기본(READ COMMITTED)인 동안 잠금(Lock)을 걸고 있는데, 이것이 그 원인일 가능성이 있습니다.
4다양화>= 0runnable아니오. 클라이언트가 쿼리를 취소하거나 연결을 닫을 때까지 해결되지 않습니다. SPID는 중단될 수 있습니다. 그러나 중단하는데 30초 정도 걸립니다.블로킹 체인의 헤드에 있는 SPID의 sysprocesses의 hostname 열(Column)은 블로킹 중인 SPID 중 하나와 같습니다.
50x0000>0rollback예.이 SPID의 Profiler(프로필러) 추적(Trace)에서 주의 신호를 볼 수 있는데, 이는 쿼리 시간 제한 또는 취소가 일어났거나 단순히 롤백 문이 실행되었음을 나타냅니다.
60x0000>0sleeping결국, Windows NT가 세션이 더 이상 활성화되어 있지 않다고 확인하면 SQL Server 연결은 끊어집니다.sysprocesses의 last_batch 값은 현재 시간보다 훨씬 앞섰습니다.

일반 블로킹 시나리오 및 해결책

아래에 나열된 시나리오에는 위의 표에 있는 특성이 있습니다. 이 절에서는 해당되는 경우 추가 세부 사항 및 해결 방법을 제공합니다.
1.실행 시간이 긴 일반 실행 쿼리에 의한 블로킹 

해결책: 
이러한 유형의 블로킹 문제에 대한 해결책은 쿼리를 최저화하는 방법을 찾는 것입니다. 사실 이러한 유형의 블로킹 문제는 성능 문제일 수 있으므로 성능 문제의 관점에서 해결해야 합니다. 쿼리의 실행 시간이 오래 걸리는 문제를 해결하는 방법은 Microsoft 기술 자료에 있는 다음 문서를 참조하십시오.
243589 INF: Troubleshooting Slow-Running Queries on SQL Server 7.0
전반적인 응용 프로그램 성능 문제 해결에 대한 내용은 Microsoft 기술 자료에 있는 다음 문서를 참조하십시오.
224587 INF: Troubleshooting Application Performance with SQL Server
다른 사용자를 블로킹하는 실행 시간이 긴 쿼리가 있는데 이를 최적화할 수 없으면 이를 OLTP 환경에서 의사 결정 지원 시스템으로 이동하십시오.
2.트랜잭션 중첩 수준(Nesting Level)의 추적(Trace)을 놓친 Sleeping 상태의 SPID에 의한 블로킹 

이러한 블로킹 유형은 일시 정지(Sleeping)되었거나 명령을 기다리는(Waiting) SPID에서 식별될 수 있으나 트랜잭션 중첩 수준(Nesting Level)(@@TRANCOUNT, sysprocesses에서 open_tran)은 0보다 큽니다. 이는 응용 프로그램에서 쿼리 시간 제한을 겪거나 필요한 수만큼의 ROLLBACK 및/또는 COMMIT 문을 실행하지 않고 취소를 실행할 경우에도 발생합니다. SPID가 쿼리 시간을 제한하거나 취소를 받으면 이는 현재 쿼리 및 일괄 처리를 종료하지만 트랜잭션을 자동으로 롤백하거나 커밋하지 않습니다. SQL Server는 취소 중인 단일 쿼리로 인해 전체 트랜잭션을 단순히 롤백해야 한다고 간주할 수 없으므로 응용 프로그램은 이에 대한 책임이 있습니다. 쿼리 시간을 제한하거나 취소하는 것은 Profiler(프로필러) 추적(Trace)에서 SPID에 대해 ATTENTION 신호 이벤트로 나타납니다. 

이를 표시하려면 Query Analyzer(쿼리 분석기)에서 다음과 같은 간단한 쿼리를 실행하십시오. 

BEGIN TRAN
SELECT * FROM SYSOBJECTS S1, SYSOBJECTS S2

-- Issue this after canceling query
SELECT @@TRANCOUNT
ROLLBACK TRAN
쿼리가 실행 중인 동안 빨간색의 Cancel 단추를 누릅니다. 쿼리가 취소된 다음 SELECT @@TRANSCOUNT는 트랜잭션 중첩 수준(Nesting Level)이 하나임을 나타냅니다. 이것이 DELETE 또는 UPDATE 쿼리이거나 HOLDLOCK가 SELECT에 사용된 경우에는 얻은 잠금(Lock)이 계속 유지됩니다. 위의 쿼리에서조차 다른 쿼리를 얻고 트랜잭션 초기 잠금(Lock)을 건 경우에 위의 SELECT가 취소되어도 계속 유지됩니다. 

해결책: 

응용 프로그램은 제대로 트랜잭션 중첩 수준(Nesting Level)을 관리해야 하는데 그렇게 하지 않으면 이러한 방식으로 쿼리 취소 다음에 블로킹 문제를 일으킬 수 있습니다.
사실 이러한 유형의 블로킹 문제 또한 성능 문제일 수 있으므로 성능 문제의 관점에서 해결해야 합니다. 쿼리 실행 시간이 줄어들면 쿼리 시간 제한 또는 취소가 일어나지 않습니다. 시간 제한 또는 취소 시나리오가 발생할 때 응용 프로그램에서 이를 처리하는 것도 중요하지만 쿼리의 성능을 확인하여 이점을 얻을 수도 있습니다. 

쿼리의 실행 시간이 오래 걸리는 문제를 해결하는 방법은 Microsoft 기술 자료에 있는 다음 문서를 참조하십시오.
243589 INF: Troubleshooting Slow-Running Queries on SQL Server 7.0
전반적인 응용 프로그램 성능 문제 해결에 대한 내용은 Microsoft 기술 자료에 있는 다음 문서를 참조하십시오.
224587 INF: Troubleshooting Application Performance with SQL Server
다른 사용자를 블로킹하는 실행 시간이 긴 쿼리가 있는데 이를 최적화할 수 없으면 이를 OLTP 환경에서 의사 결정 지원 시스템으로 이동하십시오.
3.모든 결과 행을 완료로 반입하지 못한 해당 클라이언트 응용 프로그램의 SPID에 의한 블로킹 

이 문제는 응용 프로그램을 제대로 설계하지 못해 일어납니다. 쿼리를 서버에 보낸 다음 모든 응용 프로그램은 모든 결과 행을 즉시 완료로 반입해야 합니다. 응용 프로그램에서 모든 결과 행을 반입하지 않으면 잠금(Lock)은 다른 사용자를 블로킹하면서 테이블에 남습니다. 투명하게 SQL 문을 서버에 제출하는 응용 프로그램을 사용하는 경우 응용 프로그램은 모든 결과 행을 반입해야 합니다. 그렇게 하지 않으면(그리고 이렇게 하도록 구성되어 있지 않으면) 블로킹 문제를 해결할 수 없습니다. 이러한 문제를 피하려면 제대로 작동하지 않는 응용 프로그램을 보고 또는 의사 결정 지원 데이터베이스로 제한할 수 있습니다. 

해결책: 

결과의 모든 행을 완료로 반입할 수 있도록 응용 프로그램을 다시 작성해야 합니다.
4.분산 클라이언트/서버 교착 상태에 의한 블로킹 

전형적인 교착 상태와는 달리 분산 교착 상태는 RDBMS 잠금(Lock) 관리자로 감지할 수 없습니다. 이는 교착 상태에 관련된 유일한 리소스는 SQL Server 잠금(Lock)이라는 사실 때문에 일어납니다. 교착 상태의 다른 측면은 클라이언트 응용 프로그램 수준에서 일어나는데, SQL Server는 이에 대해 제어할 수 없습니다. 다음은 이러한 문제가 발생할 수 있는 두 가지 예제 및 응용 프로그램에서 이를 피할 수 있는 방법입니다. 

a.단일 클라이언트 스레드와의 클라이언트/서버 분산 교착 상태 
클라이언트에 열린 연결이 여러 개 있고 단일 실행 스레드가 있으면 다음과 같은 분산 교착 상태가 일어날 수 있습니다. 간단히 여기서 사용되는 "dbproc" 용어는 클라이언트 연결 구조를 의미합니다. 

 SPID1------잠금(Lock)으로 ------->SPID2
  /\          블로킹됨        (클라이언트로 결과
  |                            기록 대기)
  |                                 |
  |                                 |                           서버측
  | ================================|==================================
  |     <-- 단일 스레드 -->         |                     클라이언트측
  |                                 \/
 dbproc1   <-------------------   dbproc2
 (다음 행                      (dbproc1에서 효과적으로 블로킹되어
  반입 대기)                    실행하기 위해 단일 스레드 실행 대기)
위의 경우 단일 클라이언트 응용 프로그램 스레드에는 열린 연결이 두 개 있습니다. 이는 비동기적으로 SQL 작업을 dbproc1에 제출합니다. 이는 진행하기 전에 반환하기 위해 호출을 기다리지 않음을 의미합니다. 그러면 응용 프로그램은 dbproc2에서 다른 SQL 작업을 제출하고 결과를 기다려 반환된 데이터를 처리합니다. 데이터가 되돌아 오기 시작하면(어떤 dbproc이 먼저 응답하든지 간에, 이를 dbproc1로 간주) 그 dbproc에 반환된 모든 데이터가 완료될 때까지 처리합니다. SPID1이 SPID2에서 걸고 있는 잠금(Lock)에서 블로킹될 때까지 두 쿼리가 서버에서 비동기로 실행되고 있으므로 dbproc1에서 결과가 반입됩니다. 이 때 dbproc1은 더 많은 데이터를 무한정 기다립니다. SPID2는 잠금(Lock)에서 블로킹되지만 데이터를 그 클라이언트인 dbproc2로 보내려고 합니다. 그러나 응용 프로그램 실행의 단일 스레드가 dbproc1에서 사용되므로 dbproc2는 응용 프로그램 계층의 dbproc1에서 효과적으로 블로킹됩니다. 리소스 중 SQL Server 리소스만 관련되어 있으므로 SQL Server가 감지하거나 해결할 수 없는 교착 상태가 발생합니다.
b.각 연결마다 스레드가 있는 클라이언트/서버 분산 교착 상태 

클라이언트의 각 연결마다 별도의 스레드가 있어도 이 분산 교착 상태의 변형이 다음에서와 같이 계속 발생합니다. 

SPID1--------잠금(Lock)으로 -------->SPID2
  /\           블로킹됨        (네트 쓰기 시 대기)               서버측
  |                                 |
  |                                 |
  | INSERT                          |SELECT
  | ================================|==================================
  | <-- 각 dbproc 당 하나의  -->    |                      클라이언트측
  |           스레드                \/
 dbproc1   <-----데이터 행-----    dbproc2
 (삽입 시                      (dbproc1에서 블로킹되어 버퍼에서
  대기)                         행 읽는 작업 대기)
이 경우는 예제 A와 비슷합니다. 단, dbproc2 및 SPID2는 한번에 한 행씩 처리하고 동일한 테이블에서의 INSERT, UPDATE 또는 DELETE 문에 대해 각 행을 버퍼를 통해 dbproc1으로 전달할 의도를 가지고 SELECT 문을 실행하고 있습니다. 결국, SPID1(INSERT, UPDATE 또는 DELETE 수행)은 SPID2(SELECT 수행)에서 걸고 있는 잠금(Lock)으로 블로킹됩니다. SPID2는 클라이언트 dbproc2에 결과 행을 기록합니다. 그러면 Dbproc2는 버퍼에 있는 행을 dbproc1으로 전달하려고 하지만 dbproc1이 사용 중임을 알게 됩니다(이는 SPID2에 의해 블로킹된 SPID1에서 현재 INSERT를 완료하기를 기다리도록 블로킹됨) 이 때 dbproc2는 SPID(SPID1)가 SPID2에 의해 데이터베이스 수준에서 블로킹된 dbproc1에 의해 응용 프로그램 계층에서 블로킹됩니다. 리소스 중 SQL Server 리소스만 관련되어 있으므로 다시 한번 SQL Server가 감지하거나 해결할 수 없는 교착 상태가 발생합니다.
예제 A 및 B는 둘 다 응용 프로그램 개발자가 알고 있어야 하는 기본적인 문제입니다. 개발자는 이러한 경우를 제대로 처리할 수 있는 응용 프로그램을 작성해야 합니다. 

해결책: 

두 가지 확실한 해결책은 쿼리 시간 제한을 사용하거나 바운드 연결을 사용하는 것입니다. 

쿼리 시간 제한 
쿼리 시간 제한이 제공되었을 때 분산 교착 상태가 발생하면 시간 제한이 일어날 때 교착 상태가 중단됩니다. 쿼리 시간 제한 사용에 대한 자세한 내용은 DB-Library 또는 ODBC 설명서를 참조하십시오.
바운드 연결 
이 기능을 통해 여러 개의 연결이 있는 클라이언트는 단일 트랜잭션 공간으로 바인드할 수 있으므로 연결은 서로 블로킹하지 않습니다. 자세한 내용은 SQL Server 7.0 온라인 설명서의 "Using Bound Connection" 항목을 참조하십시오.
5."골든" 또는 롤백 상태에 있는 SPID에 의한 블로킹 

중단되었거나 사용자 정의 트랜잭션 외부에서 취소된 데이터 수정 쿼리는 롤백됩니다. 이는 또한 클라이언트 컴퓨터가 다시 시작되고 해당 네트워크 세션 연결이 끊어지질 때 그 부작용으로서 발생합니다. 마찬가지로 교착 상태의 대상으로 선택된 쿼리는 롤백됩니다. 데이터 수정 쿼리는 종종 변경 사항이 초기에 적용되었을 때보다 더 빠르게 롤백될 수 없습니다. 예를 들어, DELETE, INSERT 또는 UPDATE 문이 몇 시간 동안 실행 중이었으면 롤백하는데 최소한 한 시간은 걸립니다. 변경 사항은 완전히 롤백되거나 데이터베이스에서의 트랜잭션 및 실제 무결성은 보완되므로 이는 예상했던 동작입니다. 이 동작은 반드시 발생해야 하므로 SQL Server는 SPID를 "골든" 또는 롤백(이를 중단하거나 교착 상태 대상으로 선택할 수 없음을 의미) 상태로 표시합니다. ROLLBACK 명령을 나타내는 sp_who의 출력을 관찰하여 이를 확인할 수 있습니다. sysprocesses의 Status 열은 sp_who 출력 또는 SQL Enterprise Manager(엔터프라이즈 관리자) 현재 작업 화면에도 나타나는 ROLLBACK 상태를 나타냅니다. 이 정보를 볼 수 있는 가장 확실한 방법은 문제의 블로킹 SPID의 DBCC PSS를 조사하고ec_stat 값을 관찰하는 것입니다. "골든" SPID는 ec_stat 값에 0x800를 가집니다. 기타 일반 ec_stat 값은 이 기사의 "DBCC PSS 출력을 확인합니다." 절에 나열되어 있습니다. 

해결책: 

SPID가 변경 사항을 롤백할 때까지 기다려야 합니다. 

서버가 이 작업 중간에 종료되면 데이터베이스는 복구 모드에서 다시 시작되고 열린 모든 트랜잭션이 처리될 때까지 액세스할 수 없습니다. 시작 복구는 런타임 복구로서 트랜잭션마다 걸리는 것과 같은 시간이 걸리고 데이터베이스는 이 기간 동안 액세스될 수 없습니다. 그러므로, 서버를 강제로 종료하여 롤백 상태에 있는 SPID를 수정하면 성능이 저하됩니다. 

이러한 상황을 피하려면 바쁜 시간에 OLTP 시스템에서 대규모 일괄 처리 INSERT, UPDATE 또는 DELETE 작업을 수행하지 마십시오. 가능하면 이러한 작업을 한가한 시간에 수행하도록 하십시오.
6.고아가 된 연결에 의한 블로킹 

클라이언트 응용 프로그램이 트랩되거나 클라이언트 워크스테이션이 다시 시작되면 서버에 대한 네트워크 세션은 몇몇 조건 하에서 즉시 취소되지 않을 수도 있습니다. 서버의 측면에서 클라이언트는 계속 존재하는 것으로 나타나고 얻은 모든 잠금(Lock)은 계속 유지되고 있는 것으로 나타납니다. 자세한 내용은 SQL Server 7.0 온라인 설명서에 있는 "Orphaned Connections" 항목을 참조하십시오. 

해결책: 

클라이언트 응용 프로그램이 해당 리소스를 제대로 정리하지 않고 연결이 끊어진 경우 KILL 명령을 사용하여 SPID를 종료할 수 있습니다. KILL 명령은 SPID 값을 입력으로 받습니다. 예를 들어, SPID 9를 중지하려면 다음 명령을 실행하면 됩니다. 

KILL 9

참고: KILL 명령은 KILL 명령에 대한 검사 간의 간격으로 인해 완료하는데 30초 정도 걸립니다.

응용 프로그램의 블로킹 문제 관련

블로킹 문제가 발생했을 때 서버 측 조정 및 플랫폼 문제에 중점을 두는 경향이 있습니다. 그러나 이는 일반적으로 해결책을 제시하지는 않으며 클라이언트 응용 프로그램 및 제출하는 쿼리 검사에 기울일 수 있는 시간과 노력을 빼앗을 수 있습니다. 데이터베이스 호출에 대해 응용 프로그램에서 노출하는 가시성 수준에 관계없이 블로킹 문제에서는 응용 프로그램에서 제출한 정확한 SQL 문 및 쿼리 취소, 연결 관리, 모든 결과 행 반입 등에 관한 응용 프로그램의 동작이 정확한지 조사가 이루어져야 합니다. 개발 도구가 연결 관리, 쿼리 취소, 쿼리 시간 제한, 결과 반입 등에 대한 명시적인 제어를 허용하지 않은 경우 블로킹 문제를 해결할 수 없습니다. SQL Server, 특히 업무에 중요한 OLTP 환경에 대한 응용 프로그램 개발 도구를 선택하기 전에 이러한 가능성을 세밀하게 조사해야 합니다.

데이터베이스 및 응용 프로그램의 설계 및 구성 단계에서 이러한 상황을 매우 신중하게 검토해야 합니다. 특히, 리소스 사용, 격리 수준(Isolation Level) 및 트랜잭션 경로 길이를 각 쿼리마다 평가해야 합니다. 각 쿼리 및 트랜잭션은 가능한 한 라이트웨이트이어야 합니다. 적합한 연결 관리 규칙을 적용해야 합니다. 그렇게 하지 않으면 응용 프로그램은 사용자 수가 적을 때는 좋은 성능을 내는 것처럼 보이지만 사용자 수가 급증하면 성능이 확연하게 저하될 수 있습니다. 

제대로 된 응용 프로그램 및 쿼리 설계를 통해 Microsoft SQL Server는 수천 명의 동시 사용자를 거의 블로킹하지 않고 단일 서버에서 지원할 수 있습니다. 자세한 내용은 SQL Server 7.0 온라인 설명서에 있는 "Application Design" 및 "Understanding and Avoiding Blocking" 항목을 참조하십시오. 수많은 사용자들이 접속하는 성공적인 사이트는 일반적으로 이 항목에서 설명한 기술을 사용합니다.




WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

DB Lock관련해서 sp_lock부분을 조금 이용하여 아래 LOCK걸린구문 찾는 쿼리를 한번 만들어 보았다.

TOP 1 부분이 좀 애석하긴 한데 그래도 이정도가 어디야~~~


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


declare @spid int = 0


select top 1 @spid = spid --, dbid, ObjId, IndId, Type, Resource, Mode, Status 

from (

select convert (smallint, req_spid) As spid,

rsc_dbid As dbid,

rsc_objid As ObjId,

rsc_indid As IndId,

substring (v.name, 1, 4) As Type,

substring (rsc_text, 1, 32) as Resource,

substring (u.name, 1, 8) As Mode,

substring (x.name, 1, 5) As Status


from master.dbo.syslockinfo,

master.dbo.spt_values v,

master.dbo.spt_values x,

master.dbo.spt_values u


where   master.dbo.syslockinfo.rsc_type = v.number

and v.type = 'LR'

and master.dbo.syslockinfo.req_status = x.number

and x.type = 'LS'

and master.dbo.syslockinfo.req_mode + 1 = u.number

and u.type = 'L') a where a.Mode = 'X'

group by spid --, dbid, ObjId, IndId, Type, Resource, Mode, Status


PRINT '@spid > ' + CONVERT(VARCHAR(5), @spid)


if @SPID > 0

begin

   DBCC INPUTBUFFER(@spid)

end


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

@spid > 0

혹은

Language Event | 0 | exec up_tRecvOrdSys 'RBC', '',1


요로케 나올것이다.


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

MSSQL 사용하면서 주로 즐겨쓰는 쿼리 단축키에 대해서 한번 정리해 볼까한다.

뭐 정리라 할건 없고 단순히 등록해 단축키로 간단히 사용하는 방법으로 

지난 5월 한국DB진흥회 무상 MSSQL교육시 정원혁 강사가 소개해 준 내용이기도 하다.

 

 

 

먼저 Tools > Options 로 이동한다.

 

 

 

 

Options에서 Environment > Keyborad 이동한 다음 오른쪽 표에 나오는 Ctrl + 3, 4, 5 에 위 항목을 각각 입력하고 OK누르면 끝이다.

 

참고로 Ctrl + 1, 2는 기본 내장된 쿼리로 수정이 되지 않는다.(적어도 내가 했을땐)

 

자 그럼 실제로 단축키를 이용했을때 나온 결과를 확인해 보도록 하자.

 

 

1. Ctrl + 3(선택한 테이블의 TOP 100 항목을 조회한다. [SELECT TOP 100 * FROM])

 

 

 

 

2. Ctrl + 4(선택한 테이블의 ROWS, 저장용량, 인덱스 사이즈등이 표시된다.[sp_spaceused]. 테이블 앞에 dbo가 붙으면 조회 안됨)

 

 

3. Ctrl + 5(선택한 테이블의 인덱스 상황등이 표시된다.[sp_helpindex]. 테이블 앞에 dbo가 붙으면 조회 안됨)

 

 

 

 

 

위와 같이 나온 결과를 각각 확인할 수 있다.

처음엔 손에 안익어 적응하기까지 하루이틀 정도가 걸렸던거 같은데 적응하고 나니 쿼리 짜는 속도 그리고

해당 테이블이 어떤 컬럼을 갖고 있는지 총 데이터는 얼마나 있는지 그리고 인덱스는 어떻게 걸려있는지 등을 빠르게 이해할수있어서

정말 편하게 잘 이용하고 있다.

강추 하고 싶다 ^^;

 

2023-07-25 내용추가

sp_helptext : 프로시저 내용을 표시함, 개인적으로는 Ctrl + 6 으로 사용중임


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

아래와 같이 날려주면 된다.

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

select a.name, b.text 

from sys.sysobjects a inner join sys.syscomments b on a.id = b.id

where a.xtype = 'P'

and a.category = 0

and b.text like '%검색할내용%'

'030. Database > 02. MS_SQL' 카테고리의 다른 글

[MSSQL] DB LOCK 걸린 SQL 알아보기  (0) 2012.09.05
[MSSQL] 쿼리 단축키 이용  (3) 2012.08.22
[MSSQL] Merge Table  (0) 2012.08.17
[MSSQL] 데이터 정렬관련  (0) 2012.08.12
[MSSQL] View 테이블에 index를 걸자  (0) 2012.07.11

WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

--Create a target table

CREATE TABLE Products

(

ProductID INT PRIMARY KEY,

ProductName VARCHAR(100),

Rate MONEY

GO

--Insert records into target table

INSERT INTO Products

VALUES

(1, 'Tea', 10.00),

(2, 'Coffee', 20.00),

(3, 'Muffin', 30.00),

(4, 'Biscuit', 40.00)

GO

--Create source table

CREATE TABLE UpdatedProducts

(

ProductID INT PRIMARY KEY,

ProductName VARCHAR(100),

Rate MONEY

GO

--Insert records into source table

INSERT INTO UpdatedProducts

VALUES

(1, 'Tea', 10.00),

(2, 'Coffee', 25.00),

(3, 'Muffin', 35.00),

(5, 'Pizza', 60.00)

GO

SELECT * FROM Products

SELECT * FROM UpdatedProducts

GO



MERGE Products AS TARGET

USING UpdatedProducts AS SOURCE 

ON (TARGET.ProductID = SOURCE.ProductID) 

WHEN MATCHED AND TARGET.ProductName <> SOURCE.ProductName 

OR TARGET.Rate <> SOURCE.Rate THEN 

UPDATE SET TARGET.ProductName = SOURCE.ProductName, 

TARGET.Rate = SOURCE.Rate

WHEN NOT MATCHED BY TARGET THEN 

INSERT (ProductID, ProductName, Rate) 

VALUES (SOURCE.ProductID, SOURCE.ProductName, SOURCE.Rate)

WHEN NOT MATCHED BY SOURCE THEN 

DELETE;


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


Merge 테이블 사용할 기회가 생겨 구글링 해보았음.

좋은 예제인거 같아서 올려봄.


[참고] http://www.mssqltips.com/sqlservertip/1704/using-merge-in-sql-server-to-insert-update-and-delete-at-the-same-time/

[참고] http://msdn.microsoft.com/en-us/library/bb510625.aspx



WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,