SQL Server .Net Integration

 

처음 소개 되는 내용은 SQL Server 2000에서 xp_...로 시작하는 외부 DLL을 사용하는 sp를 만들어 보셨거나, 알고 계실 겁니다.

거기에 해당되는 내용입니다. .Net을 이용해 DLL을 만든 후 SQL Server 2005에서 사용하는 방법에 대해 배웁니다.

 

간략하게 사용 하기 위한 절차를 보면,

-         Dll 파일(assembly라고 부릅니다.), assembly SQL Server 2005 cataloging(등록하는 거라고 생각하시면 됩니다.)합니다.

-         등록된 assembly를 이용하여 UDF(User Define Function)을 만듭니다.

 

Assembly는 세가지 레벨의 permission을 가집니다.

-         Safe (Default)

-         External access : network이나 file system을 접근하는 경우

-         Unsafe : WIN32 DLL이나 COM Object call하는 경우

 

Assembly dependencies

-         등록하는 Assembly가 참조하는 다른 dll이 있다면 그 DLL 역시 SQL Server에 자동으로 cataloging이 됩니다. 단 자동으로 등록된 assembly default visible 값이 0이므로, object explorer에서는 보이지 않고, sys_assemblies 테이블을 직접 select 해야 보입니다.

-         Visible 속성값을 1로 바꿔 보이게 하여 사용할 수도 있습니다.

 

 

그럼 간략하게 만드는 방법을 보면

일단 예제 코드를 보면

namespace Math

{

             public class Inverter

{

             public static int Invert(int x)

{

return -x

}

            

}

}

 

이렇게 만들어 컴파일 한 후,

 

SQL Server 2005에서 위에 설명한 절차대로 등록을 합니다.

 

CREATE ASSEMBLY MetricConverter

FROM 'c:\test\Math.dll'

 

 

CREATE FUNCTION dbo.FahrenheitToCentigrade(@i float)

RETURNS float

EXTERNAL NAME Math.[Math .Inverter].Invert

 

이렇게 한 후

SELECT Invert(10)

하면 -10이 리턴되는 걸 볼 수 있습니다.

 

간단하죠?

 

일단 간략한 소개는 여기까지~~

 

추적 플래그 3502를 사용하여 SQL Server를 시작하면, Checkpoint가 실행될 때마다 정보를 SQL Server의 에러 로그에 기록한다.

 

출처 : Inside SQL Server 번역판 [p156]

'programming > MSSQL' 카테고리의 다른 글

Essential SQL Server 2005 For Developers #1  (0) 2004.12.20
DTC 오류 해결 방법  (0) 2004.08.31
DTC 통신에 문제가 있을때 Check List  (0) 2004.08.31

MS 문서를 첨부합니다. 클릭하시면 바로 확인가능합니다.

 

기존에 보지 못했던 내용들도 있어서 퍼 왔습니다.

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

 

1. 양쪽서버 모두에서 MSDTC서비스가 시작되었는지 확인.
'NET START MSDTC'

2. 서버이름으로 서로간에 정상적으로 ping이 되는지 확인 하십시요.

3. 명령창에서 cliconfg를 실행 protocol을 named pipe대신 Tcp/ip를 default로 설정.

5. 둘 중 어느 서버에서든 NIC 를 두개 이상 가진 경우 이것들이 정상적으로 설정 되었는지 확인.

6. 만약 하나의 NIC에 두개 이상의 IP가 할당된 경우 (특히 web server) 하나의 IP만 할당하여 Test .

7. 서버간의 name resolution 방식을 확인 (DNS, WINS or lmhost)
   - 만약 서로 서버를 찾지 못하는 경우 hosts or lmhost file을 수정하여 연결.

위에서 확인된 사항이 모두 확인된 경우에도 동일 error가 발생하면 다음과 같은 일반적인 DTC TroubleShooting을 시도.

1. Transaction timeout을 길게 잡아준다.(즉, 600초 또는 0)
MTS탐색기또는 구성요소서비스관리자에서 내컴퓨터를 우측마우스로 선택후 등록정보의 옵션탭에서 설정한다.

2. MSDTC버전을 확인한다.(윈도우2000은 문제없음, NT4는 SQL 6.5 SP5a이상 또는 SQL7일경우 문제없음

4. Firewall 관련
MSDTC는 RPC를 통해 작동되기 때문에 Firewall을 사이에 두고 MTS/COM+서비스와 SQL 서버가 있을 경우 다음과 같이 하여 RPC가 원활하게 작동하도록 설정한다.
(특히 Internet환경에서)
Regedt32.exe를 실행한다.(시작->실행->regedt32)
다음키와 값을 추가합니다.(Double Quotation은 제외한다.)
HKLM\Software\Microsoft\Rpc\Internet
Ports "3000-3010" REG_MULTI_SZ
PortsInternetAvailable "Y" REG_SZ
UseInternetPorts "Y" REG_SZ

TCP와 UDP Port 135번과 TCP Port 3000-3010이 열려있어야 한다.

SQL DB에 Access하기 위해 반드시 TCP/IP와 Port 1433을 사용해야 한다. (물론 1433 Port는 열려있어야 한다.)

5. Router관련
NetBios Name을 DTC에 바인딩하기 위해 DNS 또는 WINS(또는 Hosts & LMHOSTS파일)를 사용해야만 한다.

이상의 사항으로도 해결이 되지 않는 경우 MSDTC 재설치 고려.

 

출처 : http://blog.korea.com/post/blogpost.aspx?bid=sqldba&mode=view&view=board&pid=9336&index=6&cate=240

'programming > MSSQL' 카테고리의 다른 글

DTC 오류 해결 방법  (0) 2004.08.31
Isolation level  (0) 2004.08.19
미리 보는 유콘 T-SQL의 새로운 기능들  (0) 2004.08.16
Isolation level

수많은 트랜잭션에 의해 데이터는 끊임없이 변경 및 ACCESS되고 있으며 이러한 과정 속에 검색되는
데이터 값의 어디까지를 내 트랜잭션에서 처리할 것인가를 결정하기 위해 ASE에서는 isolation level를
지정할 수 있다
isolation은 다른 트랜잭션에 의해 변경되고 있는 dirty page를 읽을 수 있는가? 하나의 트랜잭션에서 검색
되는 데이터의 일관성을 유지할 것인가? 하나의 트랜잭션에서 발생되는 phantom 현상을 허용할 것인가에 따라 isolation의 level을 1,2,3으로 정의한다

o dirty read?
o nonrepeatable read?
o phatom read?
o isolation level?
o isolation 설정 방법?
o nonrepeatable 발생을 해결하려면?
o phantom read 발생을 해결하려면?

Dirty Read?

트랜잭션1이 데이터를 변경후 트랜잭션을 종료(commit또는 rollback)하지 않은 상태에서 트랜잭션2가 변경된 데이터로 접근할 수 있다

트랜잭션1이 변경한 데이터에 대해서 commit할 지 rollback할지 트랜잭션2는 알 수 없으므로 rollback과
함께 트랜잭션1이 종료한다면 트랜잭션2는 잘못된 데이터로부터 잘못된 처리를 할 수 있는 위험이 있다

이와 같이 업무 성격에 따라 Dirty Page를 다른 트랜잭션이 접근하는 것을 허용할 것인지, 안할 것인지에 따라 ioslation 0(허용)와 isolation 1(허용 안함)로 정의 할 수 있다


Nonrepeatable Read?

트랜잭션1이 select하고 있는 테이블에는 Shared lock이 걸려 있으므로 트랜잭션2는 트랜잭션1이 검색했던 페이지의 데이터를 Modify한 후 트랜잭션2를 종료(commit)할 수 있다. 이때 아직 트랜잭션을 종료하지 않은 트랜잭션1이 먼저 select한 데이터를 다시 검색했을때 같은 트랜잭션에서 같은 질의가 발생했음에도 불구하고 다른 데이터 값을 가져올 수 있다

이와 같이 동일한 트랜잭션에서 동일한 질의에 대해 검색되는 데이터 값에 대한 일관성을 유지할 것인가(isolation level 2), 아니면 유지하지 않을 것인가 (isolation level 1)에 따라 isolation level을 지정할 수 있다


Phantom Read?

트랜잭션1이 질의를 발생하여 조건에 맞는 row의 sets을 검색중인 상황에서 트랜잭션2가 같은 테이블의 다른 row의 sets(트랜잭션1이 검색하고 있지 않는 row의 sets)의 데이터 값을 변경한 후 트랜잭션을 종료 했다

트랜잭션2가 변경한 데이터 값이 우연히도 트랜잭션1의 조건절에 영향을 주는 데이터 값이라 아직 트랜잭션을 종료하지 않은 트랜잭션1이 동일한 질의를 실행시켰을 경우 처음 데이터보다 많은 rows의 set을 검색하게 된다

이와 같이 같은 트랜잭션에서 동일한 질의를 발생시켰을 때 더 많은 rows의 sets을 보게 되는 현상을 phantom 현상이라 한다

이와 같이 같은 트랜잭션에서 phantom현상을 허용할 것인지(isolation level 2) 허용하지 않을 것인지(isolation level 3)에 따라 isolation level을 정의할 수 있다


Isolation Level?

위의 세가지 현상을 허용할 것인지 허용하지 않을 것인지에 따라 isolation level을 4가지로 나눌 수 聆만?level이 높아질수록 더 많은 제약을 부여한다

 

Level 1 (Read Committed)가 SQL Server의 기본 격리 수준(Isolation Level)이다.


Dirty Read
Nonrepeatable Read
Phantom Read
Level 0
READ UNCOMMITTED
Allowed
Allowed
Allowed
Level 1
READ COMMITTED
Prevented
Allowed
Allowed
Level 2
REPEATABLE READ
Prevented
PreventedAllowed
Level 3
SERIALIZABLE
Prevented
PreventedPrevented

Level 0
변경되고 있는 데이터에 대한 정보를 실시간 보기 위한 노력으로 set transaction isolation level 0 명령에
의해 설정되며 select명령 실행 시 share page lock을 필요로 하지 않는다
Page read 시에 해당 page에 대한 어떠한 lock도 장해가 되지 않으며 select 문장의 holdlock option 또한 아무런 효과가 없다
현재 다른 트랜잭션에 의해 변경중인(exclusive page lock)page에 대해서도 read가 가능하다

Level 1
isql에서 default mode로 사용되며 select시 읽혀지는 page에 대해 순간적으로 Shared Page Lock이 걸리며 읽힌 후 바로 Lock이 해제된다
select문장에서 holdlock option을 주게 되면 page를 읽을 때 부여되는 Shared Page Lock이 바로 해제가 되지 않으며 commit/rollback 명령에 의해서만 해제된다

Level 2
같은 트랜잭션에서의 동일한 질의에 대해 동일한 결과 값을 보장해주기 위한 노력으로 select시 발생한 Shared Lock은 트랜잭션이 종료(commit or rollback)될 때까지 해제되지 않는다
Datarows lock scheme에서만 지원되며 같은 트랜잭션에서 동일한 질의에 대해 Phantom 현상을 허용한다

Level 3
실행되는 모든 select문에 대해 holdlock option을 준 효과를 가진다
따라서 트랜잭션이 종료(commit/rollback)되기 전까지는 read된 모든 page에 대해서 shared page lock이 해제 되지 않으므로 수많은 lock을 발생시킬 수 있으므로 주의해야 한다


보다 자세한 내용은 more를!!!

 

출처 : http://www.jiic.com


..more


미리 보는 유콘 T-SQL의 새로운 기능들

편집자 메모:
이 기사에서 설명된 기능들은 최종 확정된 사항이 아니며, 최종 제품 릴리즈에서는 이 기사에서 설명한 대로 되지 않을 수도 않으며, 경우에 따라서는 최종 제품 릴리즈에 아예 포함되지 않을 수도 있다.
……………………………………………………………………………………….
독자들은 대개 Visual Basic .NET이나 C#과 같은 CLR(Common Language Runtime) 기반의 언어들을 통하여 프로그램이 가능한 객체를 개발하는 새로운 기능이 코드명 유콘(Yukon)의 차기 SQL 서버 버전에 포함된다는 사실에 대하여 들었을 것이다. 그 결과로 마이크로소프트가 T-SQL을 개선하는 데 드는 노력을 줄일 것이라고 생각할지도 모르겠지만, 실제로는 그렇지 않다. CLR 기반 프로그래밍은 T-SQL이 취약한 영역에서 T-SQL을 보완해 준다. T-SQL은 지금까지 늘 데이터 처리와 집합 기반의 연산에 있어서 강력한 면모를 보여 왔으며, 여전히 그 영역에서는 대적할 자가 없다. 그렇지만 복잡한 알고리즘이나 반복 처리 등이 포함된 영역에서는 CLR 언어가 더 강력하다. 마이크로소프트가 여러 가지로 T-SQL 개선을 위해 노력을 기울이고 있는 사실이 입증하듯이, T-SQL은 앞으로도 오랫동안 활용되고 발전할 것이다.


마이크로소프트는 오래 전부터 프로그래머들이 필요로 하고 요구해 왔던 사항들에 대한 해답을 유콘에서 제공하고 있다. 유콘에서는 T-SQL 분야에 다양한 측면에서의 개선이 이루어지고 있다. 유콘 베타1에서의 관계형 엔진의 개선에는 재귀 쿼리 기능, PIVOT, UNPIVOT 연산자, 보다 기능적인 TOP 절, CROSS APPLY 연산자, OUTER APPLY 연산자 등이 지원되는 CTE(Common Table Expressions)가 포함되어 있다.


유콘에서는 INSERT, UPDATE, DELETE 문에서도 아웃풋을 반환할 수 있게 되며, WAITFOR 명령어를 사용하여 데이터 조작 명령어인 DML((Data Manipulation Language)가 적어도 한 행에 대하여 작업을 수행할 때까지 기다렸다가 다음 명령어로 진행하도록 할 수도 있고, 또는 통지(notification)가 큐에 도달하기를 기다렸다가 다음 명령어로 진행하도록 할 수도 있다.


트리거에서 오브젝트를 삭제하는 것과 같은 DDL(Data Definition Language) 관련 이벤트들을 잡아낼 수도 있으며, DML 이벤트가 발생할 때 통지를 받을 수도 있다. Try/Catch 블록에 기반을 둔 새로운 오류 처리 메커니즘의 지원으로 이전에 비해 훨씬 더 효율적으로 오류들을 관리할 수 있게 되었다. 데이터 타입에 있어서도 중요한 개선 사항들이 있는데, 새로운 XML 데이터 타입이 지원되고, 일자 데이터 타입과 시각 데이터 타입을 별도의 데이터 타입으로 지원하며, MAX라는 옵션이 지원됨으로써 varchar, nvarchar, varbinary 등과 같은 동적 컬럼에서 대형 오브젝트들을 훨씬 더 세련되게 처리할 수 있게 되었다. 그리고 마지막으로, BULK라는 새로운 rowset provider가 지원됨으로써 사용자들이 이전에 비해 보다 용이하게 파일들을 액세스할 수 있게 되었다(Rowset provider를 사용하면 사용자가 데이터 소스를 관계형으로 액세스할 수 있으며, 이는 provider에 대하여 쿼리의 결과로서 테이블을 얻게 된다는 것을 의미한다).


이번 기사는 사전 검토 차원의 기사이기 때문에 기술적으로 깊은 부분까지 설명할 수도 없고 상세한 구문에 대하여 설명할 수도 없지만, 새로운 기능들에 대하여 주요 내용들을 알려 줄 수는 있다. 유콘 베타 테스트 프로그램에 참여하고 있는 분들의 경우에는 유콘에 포함된 온라인 설명서와 Yukon Beta Readiness Kit에 포함되어 있는 "유콘 T-SQL Enhancements" 기술 문서에서 보다 자세한 내용들을 참고하기 바란다. 유콘의 발표에 가까워질수록 다음 기사들에서는 보다 상세한 내용들을 다루게 될 것이다.

 

CTE의 기능
뷰와 파생된 테이블(derived table)의 기능을 결합할 수 있다면 좋겠다는 생각을 해 본 적이 있는가? T-SQL에서 재귀 쿼리를 작성할 필요가 있었던 적은 없는가? CTE(Common Table Expressions)를 사용하면 이 두 가지가 모두 가능해진다. CTE는 명명된 테이블 식 (named table expression)이며 그 뒤에 쿼리가 온다. CTE에는 두 가지 유형이 있는데, 하나는 비재귀(nonrecursive) CTE이고, 다른 하나는 재귀(recursive) CTE이다. 비재귀 CTE는 파생된 테이블과 뷰의 특성을 혼합한 기능이다. 파생된 테이블과 함께 사용하면 쿼리에 대하여 별칭(alias)을 부여할 수 있고, 쿼리의 결과로 얻어지는 컬럼에 대해서도 별칭을 제공할 수 있으며, CTE는 외부 쿼리(outer query)가 종료된 이후에는 남아 있지 않는다. 뷰와 함께 사용하면 외부 쿼리에서 테이블 식을 두 번 이상 참조할 수 있다. 대개 두 번 이상 테이블 식을 참조할 필요가 있고 테이블 식이 데이터베이스에 남아 있는 것을 원하지 않을 때 비재귀 CTE를 사용하게 될 것이다.
예를 들어, 각 년도별로 Northwind 데이터베이스의 Orders 테이블로부터 해당 년도의 총 주문 수량과 그 전년도의 총 주문 수량을 알고자 한다고 가정해 보자. [리스트1]에 있는 코드는 CTE를 사용하여 이 결과를 얻어 내는 방법을 보여 준다. [리스트 1]의 callout A를 보면 WITH 키워드 다음에 나오는 것이 CTE의 별칭(YearlyOrders)과 결과 컬럼 별칭들이다. Body인 callout B에서 사용자가 쿼리에 대해 부여한 별칭이 사용되고 있으며, 이 쿼리는 년도별 주문 수량 정보를 반환한다. 외부 쿼리에서는 YearlyOrders의 두 인스턴스인 CurYear와 PrevYear간에 외부 조인(outer join)을 수행하여 금년도 주문과 전년도 주문을 매칭시켜 보여 준다. [그림1]에는 [리스트1]의 코드를 수행한 결과가 나와 있다.


유콘 이전의 SQL 서버 버전에서 이와 같은 결과를 얻으려면 두 가지 방법을 사용할 수 있다. 하나는 뷰를 만들고 쿼리에서 그 뷰를 두 번 참조하는 것인데, 이 방법은 데이터베이스에 남아 있는 오브젝트를 생성할 수 밖에 없는 방식이다. 또 다른 방법은 파생된 테이블을 두 개 사용하는 것인데, 이 경우에는 코드를 두 번 작성해야 한다.


재귀 CTE는 T-SQL 쿼리에서 재귀 호출 기능이 가능하도록 해 준다. 재귀 CTE의 body에는 적어도 두 개의 쿼리(member라고도 함)가 포함되며, 이 쿼리들은 UNION ALL 연산자로 연결된다. Anchor member는 SQL 서버가 한 번 호출하는 쿼리이다. Recursive member는 CTE의 이름을 참조하는데, 이는 이전의 작업 단계에서 반환된 결과 집합을 나타낸다. 쿼리가 빈 집합을 반환할 때까지 SQL 서버가 반복적으로 Recursive member를 호출한다. 비재귀 CTE의 경우에는 외부 쿼리(outer query)가 CTE의 이름을 참조하지만, 재귀 CTE의 경우에는 참조가 Anchor member를 호출한 결과와 모든 Recursive member의 호출 결과들에 대하여 UNION ALL을 수행한 결과가 된다.


[리스트 2]에 재귀 CTE의 예제가 나와 있다. 이 코드의 목적은 Northwind 데이터베이스에 있는 Employees 테이블을 검색하여 지정한 직원과 지정한 직원의 모든 직간접 부하직원들을 반환하는 것이다. Employees 테이블에는 아홉 명의 직원들에 대한 정보가 저장되어 있으며, 모든 직원들은 한 명의 관리자에게 보고를 하는 체계이며, 관리자의 employee ID는 ReportsTo 컬럼에 저장된다. Andrew (employee ID 2)는 최상위 관리자이기 때문에 ReportsTo 컬럼의 값이 NULL이다. 만약 Andrew와 그의 직간접 부하직원을 요청하면 결과에는 아홉 명의 직원들이 모두 포함될 것이다.


이것이 어떻게 동작하는지를 이해하기 위하여 [리스트 2]에 있는 코드를 살펴 보자. SQL 서버는 callout A에서 Anchor member를 호출하며, 그 결과 Andrew에 대한 행과 Andrew가 시작점이기 때문에 0이라는 값을 포함하는 lvl이라는 의사 컬럼(pseudo column)을 반환한다. Callout B에서 Recursive member는 Employees 테이블을 이전 단계에서 얻은 결과와 조인하게 되며, 그 결과 이전 단계에서 반환된 직원들의 부하직원들이 반환된다. 재귀 쿼리에서 lvl 컬럼은 해당 직원이 관리 체인 상에서 Andrew로부터 얼마나 떨어져 있는지를 보여 주기 위하여 이전 값에 1을 더해서 lvl 컬럼 값을 반환한다.


Recursive member를 첫 번째 호출(invocation)하면 Andrew의 부하직원들인 Nancy, Janet, Margaret, Steven, Laura가 반환되며, 이들의 lvl 컬럼 값은 1이 된다. 두 번째 호출하면 첫 번째 호출에서 반환된 직원들의 부하직원들이 반환되는데, 그들은 Michael, Robert, Anne이며 이 때 그들의 lvl 컬럼의 값은 2가 된다. 세 번째 호출하면 빈 결과 집합을 반환하게 되는데, 그 이유는 마지막에 반환된 직원들은 부하직원들이 없기 때문이며, 이 경우 재귀 호출이 종료된다.
CTE의 이름을 참조하는 callout C의 외부 쿼리는 Anchor member의 결과를 포함하여 모든 호출의 통합 결과를 반환한다. [리스트 2]의 코드를 수행하여 얻어지는 결과가 [그림 2]에 나와 있다. 유콘 이전 버전의 SQL 서버에서 동일한 결과를 얻기 위해서는 직원 계층 구조를 설명하기 위하여 데이터베이스에 중복 데이터를 저장해 두거나 아니면 커서와 임시 테이블을 사용하고 반복 수행 코드를 작성해야 하는데, 그렇게 하면 시간도 많이 걸리고 유지 보수도 더 어려워진다.

 

PIVOT과 UNPIVOT
새로운 PIVOT 연산자를 사용하면 행을 컬럼으로 회전시킬 수 있으며, 이 때 원한다면 그에 따른 집계를 수행할 수도 있다. 예를 들어 Orders 테이블로부터 직원별 년간 주문 수량을 반환하고자 한다고 가정해 보자. 단순한 GROUP BY 쿼리를 작성하여 그 정보를 얻을 수도 있기는 하지만, [그림 3]에서와 같이 직원별로 하나의 행이 반환되도록 하며 별도의 컬럼에 각 년도의 주문 수량을 표시하고자 한다고 가정해 보자.


PIVOT 연산자를 사용하면 사용자가 보고자 하는 년도를 지정하기만 하면 원하는 정보를 쉽게 얻을 수 있다.


WITH EmpOrders(orderid, empid,
orderyear)
AS (SELECT OrderID, EmployeeID,
YEAR(OrderDate)FROM Orders)
SELECT * FROM EmpOrders
PIVOT(COUNT(orderid) FOR
orderyear IN([1996], [1997],
[1998])) AS P
ORDER BY empid


이 쿼리에서는 CTE를 사용하여 PIVOT 연산자와 함께 사용하고자 하는 컬럼들을 격리시킨다. CTE 대신 파생된 테이블을 사용할 수도 있지만, 쿼리가 CTE를 오직 한 번만 참조하기 때문에 이 경우에는 두 가지 방법에 차이가 별로 없다.


PIVOT 연산자의 body에 있는 FOR 절에는 컬럼의 이름을 지정하는데, 이 쿼리에서는 orderyear이며, 이 값이 바로 결과로 얻어지는 컬럼들을 회전시키는 기준이 되는 컬럼이다. FOR 절 앞에는 결과 컬럼 값 계산에 사용하고자 하는 집계 함수를 지정하는데, 이 경우에는 각 주문 년도에 대한 주문 ID의 개수가 된다.


내부적으로는 PIVOT 연산자가 지정하지 않는 컬럼들을 기반으로 하여 GROUP BY를 수행하며, 이 경우에는 empid를 기반으로 하여 GROUP BY가 수행된다. 각각의 서로 다른 employee ID에 대하여 [1996], [1997], [1998] 세 개의 컬럼들을 결과로 얻게 되며, employee ID와 년도의 각 교차 지점에 주문 수량 정보가 표시된다.


UNPIVOT 연산자는 PIVOT 연산자의 반대이다. UNPIVOT 연산자는 컬럼들을 행들로 회전시킨다. 한 예로써 이전의 PIVOT 쿼리를 수행하고 FROM 절 바로 앞에 INTO #EmpOrders를 추가해서 #EmpOrders라는 이름의 임시 테이블을 만든다. 그리고 각 사원들에 대한 년간 주문 수량을 반환하고자 하며, 그 결과의 각 행에는 사원과 년도의 조합을 표시한다고 가정해 보자. [그림 4]에 생략된 형태가 나와 있다.


다음의 UNPIVOT 쿼리를 수행해 보자:


SELECT empid, CAST(orderyear AS
int) AS orderyear, numorders
FROM #EmpOrders
UNPIVOT(numorders FOR orderyear
IN([1996], [1997], [1998]))
AS P
ORDER BY empid, orderyear


Orderyear와 numorders 둘 다 결과 컬럼이 된다. Orderyear 컬럼에는 IN 절에 의해 각각의 컬럼 이름들로부터 파생된 1996, 1997, 1998 주문 년도들이 포함될 것이다.


Numorders 컬럼에는 [1996], [1997], [1998] 세 개 컬럼들에 현재 저장되어 있는 값들이 포함되며, 각각은 각 년도에 대한 주문 수량 정보를 나타낸다. CAST() 함수를 사용하여 주문 년도에 대한 컬럼 이름들을 가지고 있는 문자열을 정수로 변환한다.


새로운 구문에 익숙해지기만 하면 PIVOT과 UNPIVOT 쿼리를 작성하는 것은 간단하다. 유콘 이전 버전의 SQL 서버에서도 동일한 결과를 얻을 수 있기는 하지만 더 길고 복잡한 코드를 작성해야 한다.

 

TOP 기능의 개선
마이크로소프트는 유콘에서 TOP 옵션에 두 가지 중요한 측면에서 개선을 가져왔다. 첫 번째 추가된 기능은 TOP에 대한 인수로서 상수가 아닌 식(expression)을 기술할 수 있게 된 것이다. 아마도 많은 분들이 오랫동안 기다려 온 기능이 아닐까 싶다. 예를 들면 다음에서와 같이 쿼리가 반환하는 행의 개수를 변수로 지정할 수 있게 된 것이다:


DECLARE @n AS int
SET @n = 5
SELECT TOP(@n) * FROM Orders ORDER BY OrderID


그리고 TOP 다음에 나오는 괄호 안에 서브쿼리와 같은 더 복잡한 식을 지정할 수도 있게 되었다. PERCENT 옵션을 사용하지 않을 때에는 식의 결과는 행들의 개수를 지정하는 bigint 값이 되며, PERCENT 옵션을 사용하는 경우에는 결과는 전체 행에서 차지하는 백분율을 지정하는 0과 100 사이의 부동 소수점 값이 된다


또 다른 개선 사항으로는 사용자가 INSERT, UPDATE, DELETE 문에 TOP을 사용할 수 있게 되었다는 점이다. 예를 들어 다음 코드는 과거 이력 데이터가 저장되어 있는 큰 테이블에서 한 번에 만 개씩 행들을 삭제하는 쿼리이다.


WHILE 1=1
BEGIN
DELETE TOP(10000) FROM Sales
WHERE dt < '20000101'
IF @@rowcount <10000 BREAK
END


이 코드에서와 같이 하나의 대량 삭제 DELETE문을 작은 크기의 여러 개의 DELETE문으로 쪼개지 않으면 트랜잭션 로그가 상당히 많이 커질 수 있으며, 그 작업 중에 발생하는 행 잠금들이 전체 테이블 잠금으로 상향 조정될 수도 있다. DELETE 연산을 여러 개의 n 행들로 분리할 때는 n개 행씩 삭제하는 DELETE 작업은 각각 개별 트랜잭션으로 간주된다. 작업이 수행되는 동안 사용자가 트랜잭션 로그 백업을 수행하게 되면 트랜잭션이 종료된 후에는 SQL 서버가 그 트랜잭션 로그 공@?재사용할 수 있게 된다. 그리고 한 번 수행되는 DELETE 문의 삭제 행의 수가 작으면 대개의 경우 행 수준 잠금으로 처리되는데, 그 이유는 SQL 서버가 리소스 부족으로 인하여 전체 테이블 잠금으로 잠금 수준을 조정해야 하는 상황이 발생하지 않기 때문이다. SQL 서버 2000에서도 대량 삭제 DELETE 문을 여러 개의 DELETE 문들로 쪼개어 행들을 삭제할 수 있으며 유콘 이전 버전들에서는 SET ROWCOUNT 옵션을 사용하여 그렇게 할 수 있다. 그렇지만 새로 지원되는 TOP 옵션이 SET ROWCOUNT보다 나은 기능이다.

 

CROSS APPLY와 OUTER APPLY
CROSS APPLY와 OUTER APPLY는 외부 쿼리(outer query)의 각 행에 대하여 테이블 값 함수를 호출할 수 있도록 해 주는 새로운 관계형 연산자들이다. 원하는 경우 외부 행의 컬럼을 함수의 인자(argument)로 사용할 수도 있다. 예를 들어 다음의 코드를 수행하면 fn_custorders()라는 이름의 사용자 정의 함수(UDF)가 만들어지며, 이 함수는 인수로서 customer ID와 number를 받아 들여서 입력 받은 고객에 대한 가장 최근의 주문 요청 횟수를 포함하는 테이블을 결과로 반환한다:


CREATE FUNCTION fn_custorders
(@custid AS nchar(5), @n AS
int) RETURNS TABLE
AS
RETURN
SELECT TOP (@n) * FROM Orders
WHERE CustomerID = @custid
ORDER BY OrderDate DESC,
OrderID DESC


다음 쿼리는 CROSS APPLY 연산자를 사용하여 Customers 테이블에 있는 각 고객들에 대하여 가장 최근의 세 개의 주문을 반환한다.


SELECT C.CustomerID, C.CompanyName, O.*
FROM Customers AS C
CROSS APPLY fn_custorders
(C.CustomerID, 3) AS O
ORDER BY C.CustomerID, O.OrderDate DESC, O.OrderID DESC


이 쿼리는 결과 테이블에 현재 있는 91명의 고객들에 대하여 263개의 행을 반환한다. 이 쿼리의 경우에는 주문이 없는 고객들(FISSA와 PARIS)에 대해서는 fn_custorders() 함수가 빈 결과 집합을 반환하기 때문에 주문이 없는 고객들은 결과에서 제외된다.


만약 함수가 빈 결과 집합을 반환하는 데이터에 대하여 외부 쿼리로부터 행을 포함시키기를 원하면 CROSS APPLY 연산자 대신 OUTER APPLY 연산자를 사용하면 된다. 조건에 부합하지 않는 행들의 경우에는 함수가 반환하는 결과 컬럼들의 값은 NULL이 된다.


유콘 이전의 SQL 서버 버전들에서는 외부 쿼리의 각 행에 대하여 하나의 쿼리에서 테이블 값 함수를 호출할 수 없다. @n이 인수일 때 각 고객에 대하여 @n개의 가장 최근의 주문들을 반환하기 위해서는 동적 수행과 서브 쿼리를 사용하는 훨씬 복잡한 코드를 작성해야 하며, 그 솔루션은 성능 면에서도 좋지 않고 유지 보수 측면에서도 어려운 단점이 있다.

 

결과를 반환하는 DML문과 WAITFOR
유콘에서는 데이터를 변경하는 SQL 문들이 단순히 데이터를 수정하는 데 그치지 않고 데이터를 반환할 수도 있다. INSERT, UPDATE, DELETE문에 OUTPUT 절을 추가하여 반환하고자 하는 데이터를 지정할 수 있다. 트리거를 작성할 때 inserted 테이블과 deleted 테이블을 사용하는 방식과 유사하게 inserted 테이블과 deleted 테이블을 참조하여 확인하고자 하는 데이터를 지정하면 된다.


WAITFOR 명령어도 개선된다. SQL 서버 2000과 그 이전 버전들에서는 WAITFOR 명령어에서 사용할 수 있는 옵션이 두 가지뿐이다. 하나는 다음 명령어로 진행하기 전에 기다리는 기간을 지정하는 것이고, 다른 하나는 다음 명령어로 진행하는 일시(datetime)를 지정하는 것이다. 그렇지만 이제 유콘에서는 SQL 문을 지정할 수 있으며 다음 명령어로 진행하기 전에 그 SQL 문이 적어도 한 행을 처리할 때까지 또는 지정한 timeout 값에 도달할 때까지 기다리도록 할 수 있다.


이 두 가지 기능을 결합하면 데이터 변경 작업이 행들을 처리할 때까지 기다릴 수 있으며 데이터 변경 작업으로부터 데이터를 돌려 받을 수도 있다. 예를 들어, Queue라는 이름의 테이블에 메시지 큐를 관리한다고 가정해 보자:


CREATE TABLE Queue(
keycol int NOT NULL
IDENTITY PRIMARY KEY,
dt datetime NOT NULL
DEFAULT(GETDATE()),
processed bit NOT NULL
DEFAULT(0),
msg varchar(50) NOT NULL)


여러 프로세스들이 새로운 메시지들을 Queue 테이블에 insert할 것이다. 여러 개의 서로 다른 연결에서 다음 코드를 수행하면 된다:


WHILE 1 = 1
BEGIN
INSERT INTO Queue(msg)
VALUES('msg' +
CAST(CAST(RAND()*9999999 AS
int) AS varchar (7)))
WAITFOR DELAY '00:00:01'
END


위의 쿼리에서는 기존의 WAITFOR 사용 방식으로 WAITFOR 명령어를 사용하여 데이터를 insert하기 전에 1초씩 기다리도록 했다.


그런데 여기서 사용자가 여러 개의 메시지들을 처리하고 그 메시지들을 처리한 것으로 표시할 필요가 있다면, 여러 세션에서 [리스트 3]에 있는 코드를 수행하면 된다.


[리스트 3]의 코드는 세 가지 새로운 기능들을 사용하고 있다. 다음 명령어로 진행하기 전에 WAITFOR 명령어가 WAITFOR 명령어의 인수인 UPDATE 문이 적어도 한 행을 처리할 때까지 기다렸다가 COMMIT을 수행한다. UPDATE 문은 UPDATE된 행들의 새로운 데이터를 output으로 반환해 주며 쿼리에서 READPAST 힌트를 지정했기 때문에 잠금이 걸려 있는 행들은 그냥 지나간다.


유콘 이전의 SQL 서버 버전들에서는 READPAST 힌트를 SELECT 문에만 사용할 수 있지만, 유콘에서는 READPAST 힌트를 UPDATE 문과 DELETE 문에 대해서도 사용할 수 있으며, 그로 인해 여러 개의 프로세스들이 동시에 병렬 처리될 때 잠금이 걸려 있지 않은 행들은 처리하고, 다른 세션에서 처리 중이어서 잠금이 걸려 있는 행들은 그냥 지나갈 수 있게 되었다. 이와 유사하게 동시에 여러 프로세스들이 잠금이 걸려 있지 않은 이미 처리 완료된 메시지들을 삭제할 수 있다:


WHILE 1 = 1
WAITFOR(DELETE FROM Queue WITH
(READPAST)
OUTPUT DELETED.*
WHERE processed = 1)


만약 유콘 이전의 SQL 서버 버전들에서 큐잉 기능을 제공하고자 하는 경우에는 SQL 서버 외부에서 로직을 구현해야 한다. 앞에서 보여 준 예제들은 새로운 WAITFOR 명령어와 결과를 반환하는 DML 기능을 사용한 매우 단순한 예제들이다. 유콘에서는 완전히 새로운 큐잉 구조가 추가되며 서비스 브로커(Service Broker)라는 큐잉 플랫폼도 구현되어 있다. 이 주제는 이 기사에서 다루기에 너무 큰 주제인 까닭에 이후에 서비스 브로커에 대하여 다루는 기사들을 참고하기 바란다.


DDL 트리거와 DML 이벤트 통지
유콘 이전의 SQL 서버 버전들에서는 DDL 이벤트들에 대하여 트리거를 발생시킬 수 없다. DBA들은 오랫동안 그런 기능들을 요청해 왔으며, 주로 그 목적은 감사(auditing)와 권한이 부여된 사용자들에 의한 스키마 변경 방지를 위한 것이었다.


유콘에서는 오브젝트들을 생성하거나 삭제하는 것과 같은 DDL 이벤트들에 대해서도 서버 차원 또는 데이터베이스 차원에서 트리거를 만들 수 있다. 트리거 내에서 EventData()라는 새로운 함수를 호출하면 이벤트와 관련되는 정보(예를 들어 이벤트를 발생시킨 프로세스 ID, 발생 시각, 수행된 SQL 문)를 액세스할 수 있으며, EventData() 함수는 XML 형태로 된 정보를 반환해 준다. 예를 들어 서버 차원에서 로그인과 관련되는 이벤트를 잡아 내고자 하는 경우에는 다음과 같이 트리거를 작성하면 된다:


CREATE TRIGGER audit_ddl_logins ON ALL SERVER
FOR CREATE_LOGIN, ALTER_LOGIN,
DROP_LOGIN
AS
PRINT 'DDL LOGIN took place.'
PRINT EventData()


로그인 계정을 만들고 변경하고 삭제하는 다음 코드를 수행하면 트리거를 테스트해 볼 수 있다:
CREATE LOGIN login1 WITH PASSWORD = '123'
ALTER LOGIN login1 WITH PASSWORD = 'xyz'


DROP LOGIN login1
트리거 내에서 이벤트 데이터를 조사할 수도 있고, 작업을 롤백시키는 것과 같은 적절한 조치를 취할 수도 있다. 트리거를 삭제하고자 하는 경우에는 다음 코드를 수행하면 된다:
DROP TRIGGER audit_ddl_logins
ON ALL SERVER
이와 유사하게 데이터베이스 차원에서 특정 DDL 이벤트들 또는 모든 DDL 이벤트들을 잡아 내는 트리거를 사용할 수도 있다. 에를 들어 다음에 나오는 트리거는 트리거가 만들어진 데이터베이스에 대하여 수행되는 모든 DDL 이벤트들을 잡아 낸다:


CREATE TRIGGER audit_ddl_events ON DATABASE
FOR DDL_DATABASE_LEVEL_EVENTS
AS
PRINT 'DDL event took place in database
' + DB_NAME() + '.'
PRINT EventData()


테이블과 뷰를 만든 다음에 만든 테이블과 뷰를 삭제하는 다음 코드를 수행하면 트리거를 테스트해 볼 수 있다:


CREATE TABLE T1(col1 int)
GO
CREATE VIEW V1 AS
SELECT * FROM T1
GO
DROP TABLE T1
DROP VIEW V1


이벤트 정보를 반환하는 것뿐만 아니라, 코드가 트리거를 호출하고 DDL 이벤트가 발생했음을 알리는 메시지를 인쇄할 수도 있다.


트리거를 삭제하고자 하는 경우에는 다음 코드를 수행하면 된다:


DROP TRIGGER audit_ddl_events
ON DATABASE


트리거는 동기적으로 동작하는데, 그것은 트리거 코드의 수행이 완료되기 전까지는 트리거 수행을 유발한 애플리케이션으로 컨트롤이 돌아가지 않는다는 것을 의미한다. 또한 유콘에서는 asynchronous event consumption도 도입된다. 여러 개의 서로 다른 애플리케이션들이 어떤 프로세스가 발생시킨 이벤트(DML 이벤트도 가능함)가 발생하는 경우에 통지를 받도록 구독할 수 있다. 그리고 그 이벤트를 활성화하는 코드를 발생시킨 애플리케이션은 구독 애플리케이션들 모두가 작업을 완료할 때까지 기다리지 않고 자신의 작업을 계속할 수 있다.

 

오류 처리
오랫동안 기다려 온 또 하나의 T-SQL 개선 사항은 오류 처리 기능이다. 유콘에는 TRY/CATCH 구조가 추가됨으로써 다른 개발 환경에서 지원되는 오류 처리 기능과 유사한 기능을 구현할 수 있다. 유콘 이전의 SQL 서버 버전에서는 연결이 비정상적으로 종료되었던 오류들을 이제 유콘에서는 잡아 낼 수 있으며, 그 오류들을 세련되고 구조화된 방식으로 처리할 수 있게 되었다. 한 예로서 T1 이라는 테이블을 만들어 보자:
CREATE TABLE T1(col1 int NOT NULL PRIMARY KEY)
{리스트 4}에 있는 코드는 TRY/CATCH 기능을 사용하여 테이블에 데이터가 insert될 때 발생할 수 있는 기본 키 위반 오류(Primary key violation error) 또는 데이터 변환 오류 등과 같은 오류들을 잡아 내는 방법을 보여 준다.


TRY 구조는 트랜잭션을 갑자기 중단시키는 오류들에 대해서만 동작하기 때문에, XACT_ABORT 옵션을 ON으로 설정해야 하며 오류 처리 코드를 트랜잭션 내부에 작성해야 한다. TRY 블록에는 오류를 잡아내고자 하는 트랜잭션을 포함시킨다. 오류 발생 시에는 트랜잭션이 “failed” 상태가 된다. 사용자는 여전히 트랜잭션의 컨텍스트 내에 남아 있게 되며, SQL 서버는 잠금을 계속 유지하며 트랜잭션 작업을 되돌려 주지 않는다. 컨트롤은 가장 가까운 CATCH 블록으로 전달되며, CATCH 블록에서는 사용자가 오류를 조사하고 실패한 트랜잭션을 롤백한 다음에 적절한 조치를 취할 수 있다.
[리스트 4]의 코드를 맨 처음 수행할 때에는 오류가 발생하지 않기 때문에 CATCH 블록이 활성화되지 않는다. [리스트 4]의 코드를 두 번째 수행하면 CATCH 블록이 기본 키 위반 오류를 잡아내게 된다. 그렇지만 첫 번째 INSERT 문을 주석 처리하고 두 번째 INSERT 문을 주석 해제한 다음에 코드를 다시 수행하면 어떤 일이 일어나는지를 확인해 보기 바란다. 그 경우에는 변환 오류가 발생하게 될 것이다.


데이터 타입과 BULK Rowset Provider
유콘은 데이터 타입에 있어서도 몇 가지 흥미로운 변화를 가져 온다. 그 중 하나는 새로운 XML 데이터 타입을 도입함으로써 XML 데이터를 변수와 테이블 컬럼으로 저장하고 관리할 수 있게 되었다는 점이다. 그리고 새로운 MAX 옵션을 사용하면 명시적인 길이를 지정하지 않고 varchar, nvarchar, varbinary와 같은 동적 컬럼들을 정의할 수도 있기 때문에, LOB 데이터 타입인 text, ntext,image 데이터 타입에 대한 보다 자연스러운 대안을 가질 수 있게 되었다. MAX 옵션을 사용하면 하나의 컬럼에 최대 2GB의 데이텨를 저장할 수 있다. 여기에서 보다 자연스럽다는 것은 새로운 MAX 옵션을 사용하면 유콘 이전 버전에서와 같이 WRITETEXT, UPDATETEXT, READTEXT 등의 명령어를 사용하지 않고 일반적인 DML 문을 사용하여 크기가 큰 동적 컬럼들을 처리할 수 있다는 것을 의미한다.


또한 유콘에서는 새로운 BULK rowset provider가 지원되는데, 이 기능을 사용하면 파일을 손쉽고 세련되게 행 집합들로 처리할 수 있다.


[리스트 5]에 있는 코드를 수행해 보면 이러한 변화들을 쉽게 이해할 수 있을 것이다. [리스트 5]에 있는 코드는 TestLargeObjects라는 테이블을 만들고 그 테이블에 하나의 행을 insert한다. 다음 코드를 수행하면 XML 컬럼 x가 SELECT 쿼리의 XML 결과로 업데이트된다:


UPDATE TestLargeObjects
SET x = (SELECT * FROM Customers FOR XML AUTO)
WHERE keycol = 1


다음과 같이 BULK provider와 OPENROWSET() 함수를 사용하면 텍스트 파일을 varchar(MAX) 컬럼으로 로드할 수 있는데, 이 때 파일 경로와 SINGLE_CLOB 옵션을 다음과 같이 지정하면 된다:


UPDATE TestLargeObjects
SET vc = (SELECT vc
FROM OPENROWSET(
BULK 'c:\temp\textfile1.txt',
SINGLE_CLOB) AS CLOB(vc))
WHERE keycol = 1


SINGLE_CLOB 옵션은 하나의 텍스트 파일을 처리하여 하나의 컬럼을 가지는 단일 행으로 반환되도록 처리한다는 것을 의미한다. 이와 유사하게 SINGLE_NCLOB 옵션을 지정함으로써 유니코드 형태의 파일을 nvarchar(MAX) 컬럼으로 로드할 수도 있고, 이진 파일을 SINGLE_BLOB 옵션을 사용하여 varbinary(MAX) 컬럼으로 로드할 수도 있다.


아마도 이 중 가장 여러분을 흥분시키는 기능은 일자 데이터 타입과 시각 데이터 타입을 별도로 지원하는 것일 것이다. 다음 코드를 수행하면 일자 컬럼과 시각 컬럼을 별도로 가지는 테이블이 만들어지고 그 테이블에 하나의 행이 insert된다:


CREATE TABLE DateTimeTest(datecol date, timecol time)
INSERT INTO DateTimeTest
VALUES(CAST('2003-11-01' AS
date), CAST('10:30:59.999999'
AS time))


새로 지원되는 일자 데이터 타입과 시각 데이터 타입은 CLR 기반이며, CLR 기반이라는 것은 그 데이터 타입들이 유콘이 지원하는 .NET 구조에 기반하여 개발되었다는 것을 의미한다. 그 결과로 별도로 지원되는 일자와 시각 데이터 타입이 다양하고 유용한 메서드와 속성(property)을 제공해 준다. 예를 들어 다음에 있는 쿼리에서처럼 ConvertToString() 메서드를 date와 time 양쪽에 적용하면 지정한 포맷 문자열에 따라 date와 time 값을 표시할 수 있다:


SELECT
datecol::ConvertToString(
'MM/dd/yyyy')AS thedate,
timecol::ConvertToString(
'HH:mm:ss.fff') AS thetime
FROM DateTimeTest


[그림 5]를 보면 이 쿼리의 수행 결과가 어떻게 나오는지 확인할 수 있다. 결과 컬럼 thedate에는 MM/dd/yyyy 형태로 된 포맷화된 일자가 표시되며, thetime 컬럼에는 HH:mm:ss.fff 형태로 된 시각이 포함된다.


T-SQL의 미래
앞에서 보았듯이 유콘에는 많은 T-SQL 관련 개선 사항과 새로운 기능이 포함되어 있다. 유콘의 등장으로 독자들은 이전 버전에 비해 더 적은 양의 코드를 작성하여 이전 버전들에서와 동일한 결과를 얻을 수 있게 되며, 훨씬 더 좋은 솔루션들을 많이 확보할 수 있게 될 것이다.
집합 기반의 관계형 언어로서의 T-SQL은 지금까지도 항상 강력했었지만 앞으로는 훨씬 더 강력해질 것이다.
 
[그림 1] 해당 년도와 그 전년도의 주문 정보
 
[그림 2] Andrew와 Andrew의 직간접 부하 직원들

 
[그림 3] PIVOT 기능을 활용한 직원별 년간 주문 정보

 
[그림 4] UNPIVOT 기능을 활용한 직원별 년간 주문 정보
 
[그림 5] 일자와 시각 값 조회


리스트 1
리스트 1: CTE를 사용하여 금년도와 전년도 주문 정보를 반환하는 쿼리
USE Northwind
BEGIN CALLOUT A
WITH YearlyOrders(orderyear, numorders)
END CALLOUT A
AS
BEGIN CALLOUT B
(
SELECT YEAR(OrderDate), COUNT(*)
FROM Orders
GROUP BY YEAR(OrderDate)
)
END CALLOUT B
SELECT CurYear.orderyear, CurYear.numorders,
PrevYear.numorders AS prev
FROM YearlyOrders AS CurYear
LEFT OUTER JOIN YearlyOrders AS PrevYear
ON CurYear.orderyear = PrevYear.orderyear + 1
ORDER BY orderyear


리스트 2
리스트 2: 재귀 CTE를 사용하여 Andrew의 부하직원들을 반환하는 쿼리
WITH EmpsCTE(empid, mgrid, fname, lname, lvl)
AS
(
BEGIN CALLOUT A
SELECT EmployeeID, ReportsTo, FirstName, Lastname, 0
FROM Employees
WHERE EmployeeID = 2
END CALLOUT A
UNION ALL
BEGIN CALLOUT B
SELECT E.EmployeeID, E.ReportsTo, E.FirstName,
E.Lastname, M.lvl + 1
FROM Employees AS E
JOIN EmpsCTE AS M
ON E.ReportsTo = M.empid
END CALLOUT B
)
BEGIN CALLOUT C
SELECT * FROM EmpsCTE
END CALLOUT C


리스트 3: TRY/CATCH를 활용한 오류 처리 예제
SET XACT_ABORT ON
BEGIN TRY
BEGIN TRAN
INSERT INTO T1 VALUES(1)
-- INSERT INTO T1 VALUES('two')
COMMIT
END TRY
BEGIN CATCH TRAN_ABORT
DECLARE @err AS int
SET @err = @@error
ROLLBACK
IF @err = 2627 PRINT 'Primary key violation.'
ELSE IF @err = 245 PRINT 'Conversion error.'
ELSE PRINT 'Error ' + CAST(@err AS varchar(10))
+ ' occurred.'
END CATCH


리스트 4: 메시지들에 대하여 처리 표시를 하고 UPDATE 결과를 output으로 반환하는 코드

WHILE 1 = 1
BEGIN
BEGIN TRAN
WAITFOR(UPDATE Queue WITH (READPAST)
SET processed = 1
OUTPUT INSERTED.*
WHERE processed = 0)
-- process messages' content
COMMIT
END

 

리스트 5: LOB 테스트 테이블을 만드는 코드
CREATE TABLE TestLargeObjects(keycol int NOT NULL PRIMARY KEY,
x XML, vc varchar(MAX), nvc nvarchar(MAX), vb varbinary(MAX))
INSERT INTO TestLargeObjects(keycol)
VALUES(1)


출처 : SQL 매거진 12월호

'programming > MSSQL' 카테고리의 다른 글

Isolation level  (0) 2004.08.19
[2005. 7. 6 수정] SP 암호화 한 것 풀기...  (8) 2004.07.01
Generate Script for Table Data 찾았습니다.  (0) 2004.06.09

음... 테스트 해 봤는데 일단 테스트 SP에 대해서는 잘 되었음.

--;;

 

이거 이렇게 쉽게 풀리면 문제 있는거 아닌가.... 웅..

내가 담아온 포스트의 SP는 역슬래시 때문에 바로 실행하면 에러가 나서 수정한 내용 다시 올립니다.

 

최근에 이용해 볼 일이 있어 다시 해 봤는데... 치명적인 문제가 있네요...

SP 문자 수가 4000을 넘어가는 경우 제대로 수행이 안됩니다.

특히 큰 문제는 원본 SP가 에러가 나면서 삭제된다는 문제가 있습니다.

꼭 주의하세요~

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

SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS OFF
GO

CREATE PROCEDURE DECRYPTSP2K (@objName varchar(50))
--INPUT: object name (stored procedure,
--
-- view or trigger)
--Original idea: shoeboy <shoeboy@a
-- dequacy.org>
--Copyright ?1999-2002 SecurityFocus
--adapted by Joseph Gama
--Planet Source Code, my employer and my
--
-- self are not responsible for the use
--     of
-- this code
--This code is provided as is and for ed
--
-- ucational purposes only
--Please test it and share your results
AS
DECLARE @a nvarchar(4000), @b nvarchar(4000), @c nvarchar(4000), @d
nvarchar(4000), @i int, @t bigint
--get encrypted data
SET @a=(SELECT ctext FROM syscomments WHERE id = object_id(@objName))
SET @b='ALTER PROCEDURE '+ @objName +' WITH ENCRYPTION AS '+REPLICATE('-',
4000-62)
EXECUTE (@b)
--get encrypted bogus SP
SET @c=(SELECT ctext FROM syscomments WHERE id = object_id(@objName))
SET @b='CREATE PROCEDURE '+ @objName +' WITH ENCRYPTION AS '+REPLICATE('-',
4000-62)
--start counter
SET @i=1
--fill temporary variable
SET @d = replicate(N'A', (datalength(@a) / 2))
--loop
WHILE @i<=datalength(@a)/2
BEGIN
--xor original+bogus+bogus encrypted
SET @d = stuff(@d, @i, 1,
NCHAR(UNICODE(substring(@a, @i, 1)) ^
(UNICODE(substring(@b, @i, 1)) ^
UNICODE(substring(@c, @i, 1)))))
SET @i=@i+1
END
--drop original SP
EXECUTE ('drop PROCEDURE '+ @objName)
--remove encryption
--try to preserve case
SET @d=REPLACE((@d),'WITH ENCRYPTION', '')
SET @d=REPLACE((@d),'With Encryption', '')
SET @d=REPLACE((@d),'with encryption', '')
IF CHARINDEX('WITH ENCRYPTION',UPPER(@d) )>0
SET @d=REPLACE(UPPER(@d),'WITH ENCRYPTION', '')
--replace SP
execute( @d)

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

 

테스트 쿼리

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

 

CREATE PROCEDURE hello
WITH ENCRYPTION
AS
PRINT 'Hello World!'
GO

exec sp_helptext hello
GO

exec dbo.DECRYPTSP2K 'hello'
GO

exec sp_helptext hello

 

암호화한 것을 만든 후 helptext로 확인한 후, DECRYPTSP2K 를 실행시키면, 암호화 된 내용을 풀어서 다시 만들어 주게 된다.

그 후 다시 helptext로 확인하면 내용이 보입니다. --;;

본 sp는 테이블의 데이터를 insert할 수 있는 insert문을 자동으로 만들어 주는 매우 유용한 sp입니다.

 

쩝... 생각보다 쉽게 찾았네요 --;;

 

첨부 파일 중 sp_generate_inserts.sql을 실행하시면 sp가 하나 만들어집니다.

sp_generate_inserts.mht는 해당 홈페이지를 긁어 놓은 파일입니다. 혹시 홈페이지가 없어지면 대략 낭패이니까요.

 

sp 이름이 'sp_generate_inserts' 입니다.

 

 

사용법은 아래와 같습니다.

 

 

Example 1:To generate INSERT statements for table 'titles':
EXEC sp_generate_inserts 'titles'
Example 2:To ommit the column list in the INSERT statement: (Column list is included by default)
NOTE: If you have too many columns, you are advised to ommit column list, as shown below, to avoid erroneous results
EXEC sp_generate_inserts 'titles', @Include_Column_List = 0
Example 3:To generate INSERT statements for 'titlesCopy' table from 'titles' table:
EXEC sp_generate_inserts 'titles', 'titlesCopy'
Example 4:To generate INSERT statements for 'titles' table for only those titles which contain the word 'Computer' in them:
EXEC sp_generate_inserts 'titles', @From = "from titles where title like '%Computer%'"
Example 5:To specify that you want to include TIMESTAMP column's data as well in the INSERT statement:
NOTE: By default TIMESTAMP column's data is not scripted
EXEC sp_generate_inserts 'titles', @Include_Timestamp = 1
Example 6: To print the debug information:
EXEC sp_generate_inserts 'titles', @debug_mode = 1
Example 7:If you are not the owner of the table, use @owner parameter to specify the owner name:
NOTE: To use this option, you must have SELECT permissions on that table
EXEC sp_generate_inserts Nickstable, @owner = 'Nick'
Example 8:To generate INSERT statements for the rest of the columns excluding images:
NOTE: When using this otion, DO NOT set @include_column_list parameter to 0
EXEC sp_generate_inserts imgtable, @ommit_images = 1
Example 9:To generate INSERT statements for the rest of the columns excluding IDENTITY column:
EXEC sp_generate_inserts mytable, @ommit_identity = 1
Example 10:To generate INSERT statements for the top 10 rows in the table:
EXEC sp_generate_inserts mytable, @top = 10
Example 11:To generate INSERT statements only with the columns you want:
EXEC sp_generate_inserts titles, @cols_to_include = "'title','title_id','au_id'"
Example 12:To generate INSERT statements by ommitting some columns:
EXEC sp_generate_inserts titles, @cols_to_exclude = "'title','title_id','au_id'"
Example 13:To avoid checking the foreign key constraints while loading data with INSERT statements:
NOTE: The @disable_constraints option will disable foreign key constraints, by assuming that the source data is valid and referentially sound
EXEC sp_generate_inserts titles, @disable_constraints = 1
Example 14:To avoid scripting data from computed columns:
EXEC sp_generate_inserts MyTable, @ommit_computed_cols = 1

 

출처 : http://vyaskn.tripod.com/code.htm#inserts

우리 회사의 ASP 페이지들에서는 Transaction Required를 많이 사용하는 관계로 종종 DTC에러를 접하곤 한다.

 

워낙 많이 겪어서 이제는 아무렇지 않게 처리하곤 하는데....

일반적으로 알고 있던 방법을 다 동원해도 해결이 안됐었다.

다른 점이 있다면 web과 db server 모두 Windows 2003이라는 점!!

 

이리 저리 찾던 중 Windows 2003에서 Web과 DB서버의 DTC를 Enable하는 방법에 대한 문서를 찾았다.

 

파일로 첨부해서 올리겠습니다. 참고 하세요~

 

 

원본 링크 : http://support.microsoft.com/?kbid=555017

 

'programming > MSSQL' 카테고리의 다른 글

Generate Script for Table Data 찾았습니다.  (0) 2004.06.09
SMO(Server Management Objects)  (0) 2004.05.12
[Reference]SQL-DMO  (8) 2004.05.12

SQL Server Management Objects (SMO)

The SQL Server Management Objects, known as SMO, is the management object model for SQL Server Yukon. SMO represents significant design and architecture improvements for the SQL Server management object model. It is a simple to use, but rich object model based on .NET managed code. SMO is the primary tool for developing database management applications using the .NET platform. SMO is used by every dialog in SQL Server "Workbench" and every administrative action you can perform in SQL Server "Workbench" can also be accomplished using SMO.

The new SMO object model and the WMI APIs replace SQL-DMO. Where possible, SMO incorporates similar objects as SQL-DMO for ease of use. You can still use SQL Server Yukon Beta 1 with SQL-DMO, but SQL-DMO will not be updated to manage Yukon-specific features.

SMO and SQL-DMO

The SMO object model is a logical continuation of the work done in SQL-DMO. SMO is feature-compatible with SQL-DMO, containing many of the same objects. Where possible, the original SQL-DMO design is followed but SMO has a number of additional features beyond SQL-DMO. To achieve maximum DDL and administrative coverage for SQL Server Yukon, SMO adds more than 150 new classes.

The primary advantages of SMO are in its performance and scalability. SMO has a cached object model, which allows you to change several properties of an object before effecting the changes to SQL Server. As a result, SMO makes fewer round trips to the server, and makes its objects more flexible. SMO also has optimized instantiation, meaning that you can partially or fully instantiate objects. You can load many objects quickly by not instantiating all properties of the objects.

Unlike SQL-DMO, which has a single Application root, that keeps references to all created Server objects, SMO lets you establish multiple roots for servers without establishing a new connection. SMO implements advanced multiple-phase scripting, in addition to supporting SQL-DMO style scripting. You can also switch an object into capture mode, and capture any DDL that would be emitted for that object, without actually applying changes to the server.

SQL-DMO also has a Managed Computer object which simplifies the interface to WMI, in order to support WMI monitoring and server configuration through the SMO object interface.

'programming > MSSQL' 카테고리의 다른 글

Windows 2003에서의 DTC(분산 트랜잭션) 관련 오류  (0) 2004.05.13
[Reference]SQL-DMO  (8) 2004.05.12
[세미나:03] 세미나 내용 정리  (0) 2004.05.10

뭐 아시는 분은 다 아시겠지만...

 

요즘 제가 DMO를 이용해 C#으로 만드는게 있는데...

요넘이 기본 .Net Framework에 포함된 library가 아니라서 제대로 된 도움말 찾기가 힘들었는데...

 

MSND에 정리된 link를 발견하게 되서 올립니다.

저 같은 실수를 범하지 마시라고...

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sqldmo/dmoref_ob_3tlx.asp

 

입니다.

 

그럼 이만~

'programming > MSSQL' 카테고리의 다른 글

SMO(Server Management Objects)  (0) 2004.05.12
[세미나:03] 세미나 내용 정리  (0) 2004.05.10
SQL Server 사용자 모임  (0) 2003.12.16

음... 이전 게시물을 보시면 PPT 파일이 있습니다.

 

강의 내용이 담긴 PPT의 내용을 중복해서 정리하면 의미가 없을 것 같으므로, PPT에 없는 내용 중 제가 적은 기억 나는 내용만 남기겠습니다.

 

SQL Server 초보자 이시거나 복제에 대한 경험이 없으신 분들은 일단 복제에 대한 공부를 간략하게 보시고, PPT를 보신 후 참고 하시는 것이 좋을 것 같습니다.

 

- 복제 시 character set에 대한 고려 : 게시자와 구독자 사이의 character set 불일치로 인한 복제 오류가 발생 할 수도 있다.

- 테이블 게시를 중지하면 timestamp 컬럼을 제거할 수 있다. (자동으로 제거되지는 않는다.)

- 병합 복제 시 기본적으로 게시자의 데이터가 구독자의 데이터에 우선한다. : 두 서버가 연결되어 있지 않은 상태에서 양쪽에서 모두 데이터를 수정할 경우, 게시자의 변경을 우선하여 update 된다.

 

- 스냅샷 복제 시 한 게시가 모두 복제되기 전까지 계속 s-lock(shared lock)을 걸게 되므로, insert와 update 시 문제가 발생할 수 있다. 그러므로 게시를 작은 단위로 나눌 필요도 있다.

- 복제의 부하는 7%이하라고 보여짐(완전히 주관적인 하성희 강사님의 의견 - 여러가지 상황에 따라 많이 다를 수 있습니다.)

 

- 복제 해제 시 순서대로 정확히 되지 않으면 해제가 되지 않아 재 성성도 안되는 경우가 있음 주의할 것

- 복제가 멈출 경우 게시자의 Transaction Log를 지울 수가 없으므로 이 점에 유의

 

- 복제 시 대부분 배포 에이전트쪽에서 문제가 많이 발생한다.

- 네트웍 등의 임시적 오류의 경우 Agent의 재시작만으로 문제가 해결되는 경우가 있다.

 

- 오류는 없는 데, 복제가 지연되는 경우 -> 구독자나 배포자의 성능에 문제가 있다.

 

경험담

- 배포자의 성능이 중요하다. (실제로 배포자의 H/W를 upgrade해서 성능향상의 효과를 본 적이 있다.)

- Insert나 Update 시 복제 지연 현상이 발생했었는데... 원인은 구독자의 서버 튜닝이 잘 안되어 있는 것이 원인이었음. 즉 구독자의 서버 튜닝도 중요하다.

 

'programming > MSSQL' 카테고리의 다른 글

[Reference]SQL-DMO  (8) 2004.05.12
SQL Server 사용자 모임  (0) 2003.12.16
[세미나]SQL 고급과정 세미나 7th  (0) 2003.12.15

네이버에 카페 하나 만들었습니다.

 

아직 썰렁하지만, 관심있는 분들의 도움 부탁드립니다.

서로 자료와 Know-how를 공유할 수 있는 장이 되었으면 합니다.

 

cafe.naver.com/sqlserver

 

'프로필'을 누르신 후 '운영중인 카페'에서 'SQL Server 사용자모임'을 선택하시면 됩니다.

'programming > MSSQL' 카테고리의 다른 글

[세미나:03] 세미나 내용 정리  (0) 2004.05.10
[세미나]SQL 고급과정 세미나 7th  (0) 2003.12.15
Naming Standard  (3) 2003.12.09

좀 일찍 올렸어야 했는데... ^^;;

신청하고 오늘 세미나 갑니다.

오랫만에 또 괜찮은 주제의 세미나인거 같아서...

가서 들은 내용 정리해서 올리겠습니다. 그럼 이만~

 

나중엔 좋은 세미나도 소개 하죠~




 




강사
Time
제목
내용
 13:00~13:30
등록
 


13:30~14:20
데이터베이스 최적화
데이터베이스를 최적화하기 위해서는 내부
구조의 특성을 잘 활용해야 합니다. 이 세
션에서는 성능 향상에 도움이 되는 데이터
베이스 최적화 기법과 데이터베이스 디자
인 기법, 수평/수직 분할 기법 등에 대하여
살펴 봅니다
14:20~14:30
휴식
 
14:30~15:30
저장 프로시저 성능
저장 프로시저의 성능적인 측면에 있어서
중요한 이슈인 실행 계획 공유와 재컴파일
에 대한 이해를 돕고, 성능 향상에 도움이
되는 저장 프로시저 디자인에 있어서의 권
고 사항들에 대하여 설명합니다.
 15:30~15:40
휴식
 


15:40~16:30
SQL Server 2000의 잠금과
트랜잭션 문제 해결1
 
16:30~16:40
휴식
 
16:40~17:30
SQL Server 2000의 잠금과
트랜잭션 문제 해결2
대부분의 논의가 하나의 쿼리가 얼마나 빨
라질 수 있는 가를 다루지만, 동시에 여러
명이 한꺼번에 쿼리들을 돌리면 어떤 충돌
이 생길까요? 인덱스는 이런 잠금과 차단의
문제를 어떻게 도와줄 수 있을까요? 이 세
션에서는 잠금과 트랜잭션의 기본에 대해
서는 알고 있다는 전제에서 출발하여 중급
이상 수준에서 잠금과 차단의 문제 해결 방
법과 시스템 테이블의 사용방법을 살펴봅
니? 또한 도움 받을 수 있는 저장 프로시
저를 만드는 방법을 살펴보고, 몇 가지 특
이한 이슈에 대해 다룹니다.








ⓒ2003 mcpworld.comCorporation. All rights reserved.
본 메일은 수신동의한 메일입니다.
기타 문의사항은 webmaster@mcpworld.com 으로 보내주시기 바랍니다.
더 이상 수신을 원치 않으시면 개인정보에서 [ 수신거부] 를 눌러주십시오.

'programming > MSSQL' 카테고리의 다른 글

SQL Server 사용자 모임  (0) 2003.12.16
Naming Standard  (3) 2003.12.09
Reusing Identities  (0) 2003.12.09

음... 실제 표준으로 제정된건 아니고, 글 쓴사람이 제안하는거 같은데...

괜찮은거 같아서...

울 회사에서도 어느 정도의 naming rule을 정해서 개발을 하고 있는데(물론 어기는 사람도 가끔 있지만 --;;) 여러모로 장점이 많은데...

이 글에는 울 회사에서 사용하지 않는 rule도 있어서 함 소개합니다.

 

출처 : http://www.sqlservercentral.com/columnists/sjones/codingstandardspart1.asp

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

 

  • Databases

    Each database on a server should be named using a name that is logical and applicable to the use of the database. Since third party databases often require specific names, this specification cannot give more concrete examples of naming standards. If you are building software which may be deployed on another server, you may wish to prefix the database name with some acronym signifying your company, as in example 3.

    Examples:

    • Sales
    • Dynamics
    • IBM_SalesAnalysis

  • Backup Devices (Full Backup)

    Any file that contains a complete backup should be named in the following format:
    <database name>_<4 digit year><month><day><hour><minute><second>
    where all times are the time the backup was started. The extension for all full backup files should be ".bak". All items should include leading zeros for values whose size is less than the size of the maximum value, i.e. always include a 2 digit month.

    Examples:

    • Sales_20011015080000.bak
    • Dynamics_20010908000000.bak

  • Backup Devices (Differential Backup)

    Any file that contains a differential backup should be named in the following format:
    <database name>_<4 digit year><month><day><hour><minute><second>
    where all times are the time the backup was started. The extension for all full backup files should be ".dif". All items should include leading zeros for values whose size is less than the size of the maximum value, i.e. always include a 2 digit month.

    Examples:

    • Sales_20011015083000.dif
    • Dynamics_20010908120000.dif

  • Backup Devices (Transaction Log Backup)

    Any file that contains a transaction log backup should be named in the following format:
    <database name>_<4 digit year><month><day><hour><minute><second>
    where all times are the time the backup was started. The extension for all full backup files should be ".trn". All items should include leading zeros for values whose size is less than the size of the maximum value, i.e. always include a 2 digit month.

    Examples:

    • Sales_20011015081500.trn
    • Dynamics_20010908080000.trn

  • Logins

    All login names should follow the company standards for network login names. Currently the standard is:
    <first initial>_<last name><middle initial (if needed)>

    Examples:

    • sjones
    • bknight

  • Users

    All database user names should match the login name to which it is mapped. NO User accounts should be shared among multiple logins. Use roles instead.

    Examples:

    • sjones
    • bknight

  • Roles

    All database roles should be named for the function of the role. This may be the name of the department or the job function.

    Examples:

    • Marketing
    • PurchasingAgents

  • Tables

    All tables should be named for the function of the table. For multiple word tables, the name should be in proper case for each word. No spaces should be used in table names.

    Examples:

    • Orders
    • OrderLineItems

  • Columns

    Columns used in either tables or views should follow the same naming convention as for tables. Proper case all words with no spaces inside the name.

    Examples:

    • OrderID
    • ProductCode
    • QuantityPurchased

  • Views

    All view names should begin with a lower case "v" and then follow the same naming conventions as for a table. Proper case all words in the name with no internal spaces. If this is a view of a single table and contains all fields, then use "v" plus the table name.

    Examples:

    • vOrderDetails
    • vProduct

  • Indexes

    All indexes should be named in the following format:
    <Table name>_<index type><index number (optional)> where the table name matches the table or view to which the index is being applied. The index types are:
    Primary Key - PK
    Clustered Index - IDX
    Nonclustered Index - NDX
    Only when there is more than one nonclustered index should the index numbering be used.

    Examples:

    • Orders_PK
    • Products_IDX
    • ProductDetails_NDX
    • ProductDetails_NDX2

  • Triggers

    All triggers should contain the name of the table, an underscore followed by "tr" and the letters which represent the intention of the trigger (i for insert, u for update, d for delete). If there are more than one trigger, a numerical designation, starting with 2 should be appended to the name.

    Examples:

    • Customers_tri
    • Orders_triu
    • Products_trd
    • Products_trd2

  • User Defined Functions (UDFs)

    A user defined function should prefixed by "udf_" and then a description that logically follows the function process. The description should be proper case words with no spaces.

    Examples:

    • udf_GetNextID
    • udf_SumOrderLines

  • Defaults

    All defaults should be prefixed with "df_" and then some description of the default value. The description should be proper case with no spaces or underscores.

    Examples:

    • df_One
    • df_GetDate

'programming > MSSQL' 카테고리의 다른 글

[세미나]SQL 고급과정 세미나 7th  (0) 2003.12.15
Reusing Identities  (0) 2003.12.09
Calling COM Objects From T-SQL  (0) 2003.12.09

identity 속성인 컬럼의 경우 일반적으로 데이터를 지워도 지운 값을 비워두고 계속 사용하게 되는데 이 기사는 그 빈값을 재사용하는 방법에 대한 내용이다.

 

출처 : http://www.sqlservercentral.com/columnists/dPriyankara/reuseidentities.asp

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

 

What is the best way to Find and reuse deleted identities

 

By: Dinesh Priyankara

In most table designs, Identity columns are used to maintain the uniqueness of records. There is no problem with insertion and modification of data using an identity column. With deletions though, gaps can occur between identity values. There are several ways to reuse these deleted (removed) identity values. 

You can find a good solution in Books Online but I wanted to find a new way and my research ended up with a good solution. After several comparisons, I decided to continue with my solution. So, I'd like to share my method with you all and let you decide what solution to use.


First of all, let’s create a table called  ‘'OrderHeader'’ that has three columns. Note that the first column intID is identity type column.
 

IF OBJECT_ID('OrderHeader') IS NOT NULL
     DROP TABLE OrderHeader
GO
CREATE TABLE OrderHeader
(intID int IDENTITY(1,1) PRIMARY KEY,
strOrderNumber varchar(10) NOT NULL,
strDescription varchar(100))
 

Now let’s add some records to table. If you want, you can add small amount of records but I added 10000 records because most tables have more than 10000 records and we must always try to make our testing environment real.
DECLARE @A smallint
SET @A = 1
WHILE (@A <> 10001)
BEGIN
     INSERT INTO OrderHeader
          (strOrderNumber,
          strDescription)
          VALUES
          (‘OD-' + CONVERT(varchar(3), @A), -- Adding something for Order Number
          'Description' + CONVERT(varchar(3), @A)) -- Adding something for Description
     SET @A = @A + 1
END 

OK. Let’s delete some randomly selected records from the table.

DELETE OrderHeader WHERE intID = 9212
DELETE OrderHeader WHERE intID = 2210
DELETE OrderHeader WHERE intID = 3200
 
If you run now a simple select query against the table, you will see some gaps between the column intID values.

Now it is time to find these gaps and reuse. As I mentioned above there are two methods (or more methods if you have already done in some other way). First let’s see the BOL example.


Method 1

DECLARE @NextIdentityValue int

SELECT @NextIdentityValue = MIN(IDENTITYCOL) + IDENT_INCR('OrderHeader')
FROM OrderHeader t1
WHERE IDENTITYCOL BETWEEN IDENT_SEED('OrderHeader') AND 32766
    AND NOT EXISTS (SELECT * FROM OrderHeader t2
        WHERE t2.IDENTITYCOL = t1.IDENTITYCOL + IDENT_INCR('OrderHeader'))

SELECT @NextIdentityValue AS NextIdentityValue

Output:
NextIdentityValue
--------------------
2210
 

This is very simple query. You can find the first deleted identity value and can reuse it. But remember you have to set the IDENTITY_INSERT ON that is allowed to explicit values to be inserted into identity column.

SET IDENTITY_INSERT OrderHeader ON

INSERT INTO OrderHeader
    (intID,
    strOrderNumber,
    strDescription)
VALUES
    (@NextIdentityValue,
    ‘OD-' + CONVERT(varchar(3), @A),
    'Description' + CONVERT(varchar(3), @A))

SET IDENTITY_INSERT OrderHeader OFF
 
Now let’s see the method 2.

Method 2 

Now I am going to create another table that is called “tb_Numbers” and has only one column that contains numbers in sequence. In my most databases, I have created and used this table for many tasks. Let me come with those in my future articles.

IF OBJECT_ID('tb_Numbers') IS NOT NULL
    DROP TABLE tb_Numbers
GO
CREATE TABLE tb_Numbers
(intNumber int PRIMARY KEY)
 

Note that I have inserted 30000 records (numbers) into the table. The range is depending on the usage of this table. In my some of databases, this range was 1 to 1000000.

DECLARE @A1 int
SET @A1 = 1

WHILE (@A1 <> 30000)
BEGIN
    INSERT INTO tb_Numbers (intNumber) VALUES (@A1)
    SET @A1 = @A1 + 1
END
 

Now let’s query the gaps (or first deleted identity value) in the OrderHeader table

SELECT TOP 1 @NextIdentityValue = intNumber
FROM OrderHeader
    RIGHT OUTER JOIN tb_Numbers
    ON tb_Numbers.intNumber = OrderHeader.intID
WHERE intID IS NULL AND intNumber < = (SELECT MAX(intID) FROM OrderHeader)

SELECT @NextIdentityValue AS NextIdentityValue
Output:
NextIdentityValue
--------------------
2210
 

This is very simple query too. I have used RIGHT OUTER JOIN to join the OrderHeader table with tb_Numbers. This join causes to return all rows (numbers) from tb_Numbers table. Then I have used some search conditions (WHERE clauses) to get the correct result set.  This result set contains all missing values in intID column.  By using TOP 1, we can get the desired result.

You can do the insertion same way as I have done in method 1.


Now it is time to compare these two methods. I simply used STATISTICS IO and the EXECUTION TIME to get the evaluation.


Comparison

DECLARE @StartingTime datetime, @EndingTime datetime

Print ‘method1:’

SET STATISTICS IO ON
SET @StartingTime = getdate()

SELECT MIN(IDENTITYCOL) + IDENT_INCR('OrderHeader')
FROM OrderHeader t1
WHERE IDENTITYCOL BETWEEN IDENT_SEED('OrderHeader') AND 32766
    AND NOT EXISTS (SELECT * FROM OrderHeader t2
        WHERE t2.IDENTITYCOL = t1.IDENTITYCOL + IDENT_INCR('OrderHeader'))

SET @EndingTime = getdate()
SET STATISTICS IO OFF

SELECT DATEDIFF(ms, @StartingTime, @EndingTime ) AS ExecTimeInMS

Print ‘method2:’

SET STATISTICS IO ON
SET @StartingTime = getdate()

SELECT TOP 1 intNumber
FROM OrderHeader
    RIGHT OUTER JOIN tb_Numbers
    ON tb_Numbers.intNumber = OrderHeader.intID
WHERE intID IS NULL AND intNumber < = (SELECT MAX(intID) FROM OrderHeader)

SET @EndingTime = getdate()
SET STATISTICS IO OFF

SELECT DATEDIFF(ms, @StartingTime, @EndingTime ) AS ExecTimeInMS
Output:
Method1:

2210

Table 'OrderHeader'. Scan count 9998, logical reads 20086, physical reads 0, read-ahead reads 0.

ExecTimeInMS
------------
200

Method2:
2210

Table 'tb_Numbers'. Scan count 1, logical reads 5, physical reads 0, read-ahead reads 0.
Table 'OrderHeader'. Scan count 2, logical reads 14, physical reads 0, read-ahead reads 0.

ExecTimeInMS
------------
0
 

As per the output, there are 20086 logical reads and it has taken 200 ms for the first method. But in second method there are only 19 logical reads and the execution time is less considerable.

That’s why I selected to continue in my way. But there may be a side that I have not seen but you can see. So, try on this and see whether how this T-SQL solution suit for you.


I highly appreciate your comments and suggestion.

 

You can reach me through dinesh@dineshpriyankara.com .

'programming > MSSQL' 카테고리의 다른 글

Naming Standard  (3) 2003.12.09
Calling COM Objects From T-SQL  (0) 2003.12.09
TSQL 이야기 - UNION  (0) 2003.11.28

T-SQL을 이용해 COM Object를 호출하는 방법

 

자세한 내용은 Books Online을 참조하라니 --;;

혹시 쓸 일이 있을거 같아 본김에 퍼놓았습니다.

더 좋은 ref가 있으면 알려주심 ㄳ

 

출처 : http://www.sqlteam.com/item.asp?ItemID=322

 

Calling COM Objects From T-SQL
sqlguru on 9/13/2000 in Stored Procs
Dan (and Nathan, and a few others) writes: "I've heard/read that you can call a COM Object from within a stored proc. Could you explain how this is done?"

Yup. This is fairly straightforward; check it out.

The functions mentioned here are all well documented in SQL Server Books Online, so I'm not going to go into a lot of detail. If you have further questions, you know where to send them :)

Calling a COM object from T-SQL is pretty easy. First, you call sp_OACreate to create an instance of the object. This stored proc returns an integer value (a handle) that you'll need later.

Next, you call sp_OAMethod to invoke a method of the object. sp_OAGetProperty will retrieve the value of a property from the object; conversely, sp_OASetProperty will set the value of one of the object's properties.

While you're calling these stored procs to manipulate the object, you use sp_OAGetErrorInfo after each call to see if the object threw an error. Error handling for COM object calls is mostly a manual process, so be prepared to do a lot of typing :)

Once you're done using the object, you call sp_OADestroy to free the object. Objects that aren't explicitly freed are automatically freed by SQL Server at the end of the query batch.

Since COM and SQL Server data types don't match up exactly, I suggest you check out the topic titled "Data Type Conversions Using OLE Automation Stored Procedures" in Books Online.

Books Online also has a topic titled "OLE Automation Sample Script" that has a nice example of calling all of these procedures.

-SQLGuru

'programming > MSSQL' 카테고리의 다른 글

Reusing Identities  (0) 2003.12.09
TSQL 이야기 - UNION  (0) 2003.11.28
TSQL 이야기...  (0) 2003.11.28

UNION, UNION ALL

 

UNION ALL은 결과를 리턴하기 전에 중복되는 값을 제거하는 과정을 거치지 않아서, UNION보다 빠르다고 합니다.

즉 UNION 연산자는 중복된 값을 제거하고 데이터를 정렬 시킨다는 얘기가 되겠죠.

 

그러므로, 중복되는 값이 있어도 상관이 없는 경우라면 UNOIN보다는 UNOIN ALL을 사용해야 합니다.

'programming > MSSQL' 카테고리의 다른 글

Calling COM Objects From T-SQL  (0) 2003.12.09
TSQL 이야기...  (0) 2003.11.28
[컬럼]SQL Server에 별칭(Alias)을 달아보자  (2) 2003.11.13

SQL Server를 만진지 이제 언 3년 8개월...

 

아는게 별로 없는 상태로 회사에 입사해서, 정말 많은걸 배운거 같다.

SQL Server를 6.5부터 2000까지 써 오면서 책도 많이 보고, 경험도 많이 쌓았다.

 

나온지는 꽤 된 책이지만, 지금까지 보아온 책 중 정말 알차다는 느낌을 받은 책...

 

책 선전을 하는건 아니지만,

 

강력한 SQL 프로그래밍을 위한 Transact SQL

켄 핸더슨 지음

 

틈날때마나 조금씩 조금씩 읽으면서, 좋은 내용에는 줄도 그어가면서 봤는데...

좋은 내용들을 보다 많은 사람들과 공유하고 싶어서 내 블로에 조금씩 올리려고 한다.

 

제목은 'TSQL 이야기'...

 

주로 SQL에 관련된 이야기이기는 하지만 아무래도 SQL Server를 기반으로 하고 있어, 타 DBMS를 사용하는 분들께는 적용되지 않는 이야기들도 있겠지만... 봐두면 좋을만한 내용들을 뽑아 조금씩 소개하고 싶다.

 

'programming > MSSQL' 카테고리의 다른 글

TSQL 이야기 - UNION  (0) 2003.11.28
[컬럼]SQL Server에 별칭(Alias)을 달아보자  (2) 2003.11.13
복제 설정 시 자주 발생하는 에러  (4) 2003.11.13

마이크로소프트 TechNet 사이트에서 펀 글입니다.

 

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

 

김기홍 대리 / MCSE, MCDBA, 한국마이크로소프트 고객기술지원부

어느 날인가 고객으로부터 다급한 목소리로 전화가 걸려왔다.
"SQL Server에서 DTS (Data Transformation Service)를 수행하였을 때 원본 테이블 데이터가 사라졌어요"
아니 이럴 수가!! 이것이 사실이라면 정말 큰일인 것이다. RDMS 시스템에서 어떤 버그로 인해 데이터가 손실된다는 것은 상상조차 하기 힘든 일인데, 테이블내용이 통째로 사라지다니.. 일단 고객에게 100리나 되는 거리를 단숨에 달려갔다. 고객은 내 눈앞에서 실제로 원본 테이블내용이 사라지는 것을 시연해 주었다.
"A"라는 원본 SQL Server에서 "B"라는 대상 SQL Server로 테이블을 DTS하니 원본 테이블의 내용이 사라지는 것이다. (이때 DTS의 기본 설정은 대상 테이블이 존재 할 때, 대상 테이블을 제거 후 재생성 하는 옵션을 가지고 있었다.) 필자는 습관적으로 DTS를 수행한 클라이언트 장비에서 SQL Server 네트워크 유틸리티의 별칭을 조사해 보았다. 아니나 다를까 사건의 비밀은 거기에 존재하고 있었다.

고객은 자신의 장비에 "B"라는 이름을 가지고 "A"라는 서버를 연결하도록 설정한 "별칭"이 설정되어 있었다는 사실을 모르고 있었던 것이었다. 이런 황당한 사태를 유발한 "별칭"은 무엇일까? 이 별칭을 설명하기 위해서 MDAC과 SQL Server 클라이언트 네트워크 유틸리티에 대해 먼저 설명하고자 한다.

MDAC (Microsoft Data Access Component)이란?

Microsoft 관련 제품을 사용하다 보면, 간혹 MDAC이란 이름을 접하게 된다.
MDAC은 Windows NT4 Service Pack 4 또는 Internet Explorer 4.0 이후 출시된 대부분의 Microsoft 제품 (Windows, Office, Visual Studio, Internet Explorer 및 모든 서버 제품군)에 포함되어있으며, 사용자도 인지하지 못하는 사이에 (아니 자세히 관찰하면 제품설치 시 MDAC 설치 화면을 볼 수 있다.) 항상 상위 버전으로 자동 설치 될 뿐, 제거되거나 하위 버전으로 변경되는 경우는 거의 없다. 그럼 이 MDAC이란 무엇일까?
Web 또는 LAN 이용하여 데이터를 주고받는 클라이언트/서버 형태의 응용프로그램에서 관계형(SQL) 또는 비관계형에 상관없이 다양한 데이터 소스로부터 쉽게 정보(Information)을 통합-공유할 수 있는 ADO, OLE DB, ODBC 등의 컴포넌트들을 제공하여 준다.

MDAC의 버전

그 동안 배포된 MDAC의 버전을 살펴보면, MDAC 1.5, 2.0, 2.1, 2.5, 2.6, 2.7, 2.8등 다양한 버전이 존재하며, 또한 각 버전별 Service Pack도 존재한다. 이 많은 버전들의 MDAC을 설치하는 원칙은 매우 단순하다. 데이터를 공급 받는 클라이언트(데이터 소비자)의 MDAC 버전은 데이터를 제공하는 서버(데이터 소스)의 MDAC 버전보다 높거나 최소한 같아야 한다. 이렇게 하여야지만 데이터 소스에서 제공하는 모든 기능 및 기존 문제점들을 수용할 수 있게 된다. 일례로 자신의 장비에 MDAC 버전을 최소 어느 버전 이상으로 설치하여야 하는가는 자신의 장비에서 연결하는 최신 SQL Server 버전 및 서버에 설치된 최신 SQL Server Service Pack 버전이 포함한 MDAC 보다 같거나 높으면 된다. 추가로 요즈음 제공되는 MDAC관련 Tool의 경우 설치된 MDAC 버전을 제거하거나, 하위 버전으로 회귀하는 기능들을 제공하기도하지만 절대적인 원칙은 항상 MDAC은 상위 버전으로 변경될 뿐 하위버전으로 변경하는 것을 권장하지 않는다. (일부 클러스터 환경에서는 서버 환경에 특정 버전 이상의 MDAC 설치를 권장하지 않는 경우도 있지만..)

SQL Server의 제품 CD 및 SQL Server Service Pack CD를 살펴 보면 "x86\other\sqlredis.exe"라는 파일을 공통적으로 발견할 수 있다. 이 sqlredis.exe의 경우 최신 MDAC과 완전하게 동일하지는 않지만, 현재 설치된 SQL Server 버전에 문제없이 연결이 가능하도록 구성되었으며, 재배포 가능한 형태의 MDAC 대부분 컴포넌트를 포함하고, Remote에서 설치가 가능한 무인실행 설치 파일이다. 따라서 방화벽 클라이언트 응용프로그램들이 방화벽 또는 프락시 서버에서 공유되도록 하듯이, SQL Server 관리자들은 sqlredis.exe를 SQL Server 상에서 파일 공유하여 해당 SQL Server를 연결하고자 하는 모든 클라이언트는 이 파일(sqlredis.exe) 설치에 의해 SQL Server연결에 관련된 기본 요건을 쉽게 구성할 수 있도록 하는 것도 하나의 유용한 팁이 될 수 있다.

SQL Server를 사용하는 웹서버 및 기타 응용프로그램 서버 관리자의 경우, 잊지 말고 SQL Server Service Pack 적용 시 항상 각각의 웹서버에 이 sqlredis.exe를 수행하여 클라이언트의 MDAC 버전을 서버와 일치 시켜준다면, 향후 겪게 될 많은 문제점들을 피해 갈 수 있을 것이다.

SQL Server 클라이언트 네트워크 유틸리티

위에서 설명된 MDAC이 설치된 경우 여러분은 다음과 같은 방법에 의해 SQL Server 클라이언트 네트워크 유틸리티라는 것이 포함되어 있음을 확인할 수 있다.
    ->[시작] - [실행] 에서 "Cliconfg.exe" 을 입력 후 "확인"을 클릭
    ->이후 화면에 SQL Server 클라이언트 네트워크 유틸리티라는 창이 나타난다.
SQL Server 클라이언트 네트워크 유틸리티의 창 형태는 설치된 MDAC 버전에 따라 화면이 조금씩 틀린 점을 유의하여야 한다.

SQL Server 클라이언트 네트워크 유틸리티는 다음과 같은 용도에 사용하는 그래픽 기반 도구이며, 기본적으로 다음 네 가지의 탭을 가지고 있다.

  • 일반 탭: 지정된 서버에 대한 네트워크 프로토콜 연결을 만들고, 기본 네트워크 프로토콜을 변경가능.
  • 별칭 탭: 클라이언트가 연결하는 컴퓨터의 서버 별칭에 대한 정보를 나열.
  • DB 라이브러리 옵션 탭: 시스템에 현재 설치되어 있는 네트워크 라이브러리에 대한 정보를 표시.
  • 네트워크 라이브러리 옵션 탭: 시스템에 현재 설치되어 있는 DB 라이브러리 버전을 표시하고 DB 라이브러리 옵션의 기본값을 설정.
일반 탭의 경우 SQL Server 2000 출시 이전 MDAC에서는 Named Pipe가 SQL Server 연결 시 사용되는 기본 프로토콜 이었으나, SQL Server 2000 출시 이후 MDAC에서는 TCP/IP 가 기본 프로토콜임을 확인할 수 있다.


별칭(Alias)이란?

SQL Server 클라이언트 네트워크 유틸리티에서 재미있고, 독특한 동작방식을 가지는 것이 별칭 탭에서 설정 가능한 SQL Server 별칭이다.
SQL Server 별칭의 경우 각 SQL Server 별로 사용하는 네트워크 라이브러리 (Named Pipe, TCP/IP, Multiprotocol등)를 지정할 수 있고, 또한 사용하고자 하는 매개변수 (Named Pipe의 파이프 이름, TCP/IP의 Port 번호 등)를 지정이 가능하다. 일반적으로 별칭사용을 많이 접하는 사례는 보안 이슈에 의해 SQL Server를 1433이 아닌 다른 고정 포트로 서비스하는 경우 SQL Server의 클라이언트 (웹서버 및 데스크탑 PC등)들에게 특정 SQL Server의 TCP/IP Port를 지정하는 것은 종종 볼 수 있다. 그러나 이 별칭의 기능이 단순히 이것만 있는 것일까? 활용하기에 따라 처음에 DTS 사례에서 언급했던 것 같은 흥미로운 결과를 초래하는 경우가 많다.

별칭의 동작 방식

별칭은 각 클라이언트 별로 자신에게 설정된 사항만 적용된다.
만약 "Server1"와 "Server2"라는 SQL Server가 존재하고 "Client1"와 "Client2"라는 클라이언트 장비가 존재 할 때 "Client1"에만 서버 별칭이름을 "Server2" 그리고 서버 이름을 "Server1"로 지정 추가한 경우에, 각각의 "Client1"과 "Client2"에서 "Server1"과 "Server2"를 연결하면 어떤 서버가 연결될까? 당연히 "Client2"에서는 "Server1"과 "Server2"가 정상적으로 연결 가능. 하지만 "Client1"에서 "Server1"을 연결하는 경우에는 "Server1"이 연결되고, 별칭 사용에 의해 "Server2"를 연결한 경우 "Server1"로 연결된다. 이 때 "Client1"에서 SQL Server 명을 별도로 확인하지 않으면 자신은 "Server1"에 연결된 상태로 착각할 수 있다.

만약 세 사람이 구름 한 점 없는 푸른 하늘을 쳐다 보고 있다. 이 때 한 사람은 짙은 빨간색 색안경을, 또 한 사람은 짙은 노란색 색안경을, 그리고 나머지 한 사람은 전혀 색안경을 끼지 않은 경우 이 세 사람이 보고 있는 하늘의 색채는 푸른 빛, 붉은 빛, 노란 빛으로 보일 수 있다. 별칭 또한 마찬 가지로 푸른색(Server1)붉은색(Server2)으로 보이게 할 수 있는 색안경과 같은 역할을 한다. 하지만 각기 자기가 착용한 색안경에만 영향을 받을 뿐 다른 사람이 착용한 색안경에는 전혀 영향을 받지 않는다. 그러나 상당히 위험할 수 있는 경우는 처음에 언급된 DTS 사례처럼 자신이 색안경을 착용한지를 모르는 경우 뜻하지 않은 사태가 발생할 수 있음도 유의 하여야 한다.

별칭의 적용 사례

  1. 4대의 웹서버가 SQL Server를 사용하고 있는데 운영중인 SQL Server ("ServerA")의 장애 발생시 Standby SQL Server("ServerB")로 1~2분 내로 연결을 변경하고 싶은데 어떻게 해야 하나요? (이 때 Standby Server는 Log Shipping에 의해 운영 데이터와 15분의 차이는 있지만 ReadOnly 상태로 임시적 운영예정이어서 데이터 동기화는 큰 문제가 없습니다만 IP와 서버명을 변경하여 System을 Restart하기에는 시간이 너무 촉박합니다.)
    : 답은 간단하다. 각 웹서버에 서버 별칭은 "ServerA"로 서버 이름은 "ServerB"로 설정된 별칭을 추가하면, 별칭이 추가된 순간부터 연결되는 SQL Server Connection은 ServerB로 연결된다.
  2. 하나의 Domain을 사용하는 3000대 PC에서 SQL Server를 직접 연결하는데, SQL Server명과 IP, Port 가 모두 바뀌어야 하는 불가피한 상황이 발생 했습니다. 그런데 응용프로그램의 SQL Server 정보를 변경하여 새로 배포하지 않고, 모든 PC에서 기존의 SQL Server가 아닌 새로 변경된 SQL Server명과 IP, Port를 연결할 수 있는 방법이 없을까요?
    : 마찬가지로 방법이 그리 어려운 것은 아니다. Domain LogOn시 다음 registry를 항목을 추가하는 Domain LogOn Script를 설정 하거나, .reg 파일을 배포 및 실행하면 된다. Ex) TCP/IP Connection 사용
    -> Old SQL Server 서버명 : OLDSERVER ; IP : 10.10.10.1 ; Port : 1433
    -> New SQL Server 서버명 : NEWSERVER ; IP : 10.10.10.2 ; Port : 1064

    ----------------------------------
    Windows Registry Editor Version 5.00

    [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo]
    "OLDSERVER"="DBMSSOCN,NEWSERVER,1064"
    "10.10.10.1 "="DBMSSOCN, 10.10.10.2,1064"

    추가 사항:
    - MDAC 2.6 이상에서 Dynamic Port를 사용하고 싶은 경우 예제
    "OLDSERVER "="DBMSSOCN, NEWSERVER"

    - Named Pipe를 사용하는 경우 예제
    "OLDSERVER"="DBNMPNTW,\\\\NEWSERVER\\pipe\\sql\\query"

    - Multiprotocol을 사용하는 경우 예제
    "OLDSERVER "="DBMSRPCN,NEWSERVER"

참고로 SQL Server의 대다수 사용자들이 가장 많이 겪는 문제점들이 SQL Server의 연결과 관련된 문제이므로 아래 첨부된 웹캐스트를 활용하면 많은 도움이 될 것이다.
Support WebCast: Microsoft SQL Server 2000: Troubleshooting Connectivity  

SQL Server 2000이 출시된 이후 SQL Server 연결 시 SQL Server Name에 대한 Name Resolution이 필수적인 경우가 많아 연결 문제가 더 잦아지는 경향도 없지 않다. 이때 네트워크 구성에 따라 Hosts 또는 lmhosts 파일에 SQL Server Name을 수동 추가하는 작업으로 인해 상당수의 SQL Server 연결 문제를 해결하는 경우가 상당수 있다.

이상으로 MDAC, SQL Server 클라이언트 네트워크 유틸리티, 별칭 등에 대해 간략하게 살펴 보았다. 만약 지금까지의 내용을 개개인의 PC상에서 점검해 보면 이미 상당수의 사용자들이 SQL Server 연결과 관계된 많은 설정 및 콤포넌트들을 본인들도 인지하지 못하는 사이에 사용하고 있었음을 발견할 수 있을 것이다.

 

출처 : http://www.microsoft.com/korea/technet/resources/Technetcolumn/column_12.asp

 

'programming > MSSQL' 카테고리의 다른 글

TSQL 이야기...  (0) 2003.11.28
복제 설정 시 자주 발생하는 에러  (4) 2003.11.13
[Tip]mdf파일 만으로 DB 복구하는 방법  (0) 2003.11.12

에러 메세지

'SQL Server 엔터프라이즈 관리자이(가) XXX을(를) XXX의 배포자로 구성할 수 없습니다.

 

오류 18483: 'distributor_admin'이(가) 서버에서 원격 로그인으로 정의되어 있지 않기 때문에 XXX서버에 연결할 수 없습니다.'

라는 에러 발생시 점검해야 할 것.

- SELECT @@servername 을 통해 실제 서버이름과 일치하는지를 확인. 일치하지 않는 경우 'sp_dropserver'를 통해 서버를 drop하고 'sp_addserver 서버이름, 'local''을 이용해 서버 이름을 새로 등록한 후 서비스를 재 시작하고 다시 SELECT @@servername을 해 보면 바뀐 이름을 확인해 볼 수 있다.

- 엔터프라이즈 메니저에 서버를 등록할 때, 꼭 서버 이름으로 등록할 것 ('local'이나 ip혹은 .으로 등록하지 말것)

 

 

EXEC sp_attach_single_file_db 'pubs' , 'c:\Program Files\Microsoft SQL Server\MSSQL\Data\pubs.mdf' 

'programming > MSSQL' 카테고리의 다른 글

복제 설정 시 자주 발생하는 에러  (4) 2003.11.13
인덱스 고르는 방법  (0) 2003.10.16
[튜닝] index...  (0) 2003.10.14

이번에는 인덱스를 고르는 방법에 대한 글 입니다.

저도 아직 다 안 읽어봤는데... 역시 시간과 능력 되는 만큼만 번역해 놓겠습니다.

 

 

How to Select Indexes for
Your SQL Server Tables


by Manish Rawat

 

Indexing is one of the most crucial elements in increasing the performance of SQL Server. A well-written query will not show its effectiveness unless powered by an appropriate index or indexes on the table(s) used in a query, especially if the tables are large.

 

Indexes exist to make data selection faster, so the focus of this article is on ways you can select the best indexes for faster data retrieval. This is done in a two-step process.

(인덱스는 데이터의 검색을 빠르게 한다. 그래서, 이 글에선 빠른 데이터 검색을 위한 가장 좋은 인덱스를 선택하는 방법에 촛점을 맞춘다. 이것은 두 단계로 이루어진다.)

  • Step One: Gathering Information
    (첫번째 단계 : 정보 수집)
  • Step Two: Taking Actions on the Information Gathered 
  • (두번째 단계 : 수집된 정보를 바탕으로 작업 수행)

 

Indexing can be quite a challenging task if you are not familiar with your databases, the relationships between tables, and how queries are written in stored procedures and embedded SQL. How many companies you have worked for have a proper ERD diagram of their databases and have followed the textbook method style of programming? In the real world, time is often limited, resulting in poor SQL Server database performance.

If you have been tasked with optimizing a database's performance (at least to a respectable level), or you want to be proactive with your databases to prevent potential future performance issues, following these steps should help you in tuning tables, just as they have helped me. These steps are applicable at any stage of project, even if a deadline is just around the corner.

 

Step One (Gathering Information)

Interact with the people who know about the database and its table structures.

(데이터베이스와 그 데이터베이스의 테이블 구조에 대해 아는 사람들과 대화를 나눈다.)

If you know it already, that’s great. This is very important and makes your life easier.

(만약 이미 알고 있다면 좋은 일이다. 이것은 매우 중요하며, 작업을 쉽게 만들어 준다.)

 

1) Identify key tables, based on: (아래의 내용을 기반으로 KEY 테이블을 찾는다.)

  • Static tables (often called master tables).
    (정적 테이블 - 마스터 테이블이라 불린다.)
  • Highly transactional tables.
    (많은 트랜잭션이 발생하는 테이블)
  • Tables used within a lot of stored procedures or embedded SQL.
    (임베디드 SQL이나 저장프로시저에서 많이 사용된 테이블)
  • Tables with an index size greater then its data's size. You can use sp_spaceused with the table name to find table space usage.
    (데이터 크기보다 큰 사이트의 인덱스를 갖는 테이블. 'sp_spaceused'를 이용해서 찾을 수 있다.)
  • Top 10 or 15 big size tables. See a prior year database if available or applicable. The idea is to identify the largest tables in the database after it is in production. There is a script available at http://www.sqlteam.com/item.asp?ItemID=282 that you may find useful.
  • (전체 테이블 중 10~15위권 안의 사이즈가 큰 테이블.)

2) Identify the most frequently called stored procedures/queries and list all of the tables used by them.

(가장 자주 사용되는 저장 프로시저나 쿼리들을 찾아내고, 이 저장 프로시저나 쿼리에서 사용되는 테이블을 목록화한다.)

 

3) Get the SQL Profiler trace of :

  • Production site (if available/applicable). Running a trace on the production box during typical activity is worth the effort and will be fruitful in later analysis.

  • Testing site (if one is available/applicable).

  • Otherwise, get if from your development server.

It is advisable to write down information you collect in a document for later retrieval.

 

4) Before we dive into analyzing the information gathered, here are few things to keep in mind while tuning your tables:

  • To see the Query/Execution plans of queries, highlight them in SQL Query Analyzer (isqlw.exe) and select Display Estimated Query Plan (Cntl+L) from the Query menu. If you want to see the query plan of a stored procedure, select Show Execution Plan (Cntl+k) and execute the stored procedure. Also, turn on the “Set Statistics IO on “ command. Examining Query/Execution plans can be a bit time consuming. But you will find it easier if you really understand the database and its tables before you begin.

  • You need to have a good foundation on how clustered and non-clustered indexes work. See this URL for a good foundation on this topic: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/architec/8_ar_da2_8sit.asp

 

Preferred SQL Server Index Types

When you use Query Analyzer to produce a graphical execution plan, you will notice that there are several different ways SQL Server uses indexes.

1) Clustered Index Seek: A Clustered Index Seek uses the seeking ability of indexes to retrieve rows directly from a clustered index. In most cases, they provide the best performance on SELECT statements.

In Query Analyzer, go to pubs database. Type following query:

SELECT * FROM authors WHERE au_id LIKE'2%'

Highlight the query and press. (Cntl + L) or highlight the query and press F5. You will see the following in the “Estimated Execution Plan” tab.

Take a close look at the Argument section of the above illustration. Notice that the “UPKCL_auidind” clustered index is used to retrieve the data.

2) Index Seek: An Index Seek uses a non-clustered index to retrieve data, and in some ways, acts like a clustered index. This is because all of the data retrieved is fetched from the leaf layer of the non-clustered index, not from any of the data pages. You often see this behavior in a covering index.

In Query Analyzer, go to pubs database and type following query:

SELECT title_id, title FROM titles WHERE title LIKE 't%'

Highlight the query and press. (Cntl + L) or highlight the query and press F5. You will see the following in the “Estimated Execution Plan” tab:

In the Argument section in the above illustration, note that the “titleind” non-clustered index is used to retrieve the data.

3) Bookmark Lookup: A Bookmark Lookup uses a non-clustered index to select the data. It starts with an index seek in the leaf nodes of the non-clustered index to identify the location of the data from the data pages, then it retrieves the necessary data directly from the data pages. Leaf nodes of non-clustered indexes contain row locator that point to the actual data on data pages.

In Query Analyzer, go to the pubs database. Type following query:

SELECT * FROM titles WHERE title LIKE 't%'

Highlight the query and press. (Cntl + L) or highlight the query and press F5. You will see the following in the “Estimated Execution Plan” tab.

In the Argument section of the Index Seek, notice that the "titlecind" non-clustered index is used, but once the data pages are identified from looking them up in the leaf pages of the non-clustered index, then a Bookmark Lookup must be performed. Again, a Bookmark Lookup is when the Query Optimizer has to lookup the data from the data pages in order to retrieve it. In the Argument section of the Bookmark Lookup, note that a Bookmark Lookup called "Bmk1000" is used. This name is assigned automatically by the Query Optimizer.

4) Scans: Scans (Table scans, Index scan, and Clustered Index scans) are usually bad unless the table has very few rows and the Query Optimizer determines that a table scan will outperform the use of an available index. Watch out for scans in your execution plans.

In Query Analyzer, go to pubs database and type the following query:

SELECT * FROM employee WHERE hire_date > '1992-08-01'

Highlight the query and press. (Cntl + L) or highlight the query and press F5. You will see the following in the “Estimated Execution Plan” tab:

Notice that in this case, a Clustered Index Scan was performed, which means that every row in the clustered index had to be examined to fulfill the requirements of the query.

Now that we understand some of the basics of how to read Query Execution Plans, lets take a look at some additional information that you will find useful when analyzing queries for proper index use:

  • If you create multiple query or a stored procedure execution plans at the same time in Query Analyzer, you can compare the cost of each query or stored procedure to see which is more efficient. This is useful for comparing different versions of the same query or stored procedure.
    (쿼리분석기에서 다수의 쿼리나 저장프로시저에 대한 실행계획을 동시에 보면, 각각의 쿼리나 저장 프로시저의 비용을 보다 효과적으로 비교해 불 수 있다. 이런 방법은 같은 쿼리나 저장 프로시저의 다른 버젼들 간의 비교에 보다 유용하게 활용할 수 있다.)

 

  • Primary Key constraints create clustered indexes automatically if no clustered index already exists on the table and a non-clustered index is not specified when you create the PRIMARY KEY constraint.
    (기본키 제약조건은 테이블에 클러스터드 인덱스가 존재하지 않는 경우 클러스터드 인덱스를 자동적으로 생성한다.(역자주-7.0의 경우 넌클러스터드 인덱스였다. 2000이 되면서 바뀐 부분) 그리고 기본키 제약조건을 만들 때 넌클러스터드인덱스는 만들어지지 않는다.)
  • Non-clustered indexes store clustered index keys as their row locators. This overhead can be used as a benefit by creating a covering index (explained later). Using covering indexes requires caution.

  • A table's size comprises both the table’s data and the size of any indexes on that table.

  • Adding too many indexes on a table increases the total index size of atable and can often degrade performance.

  • Always add a clustered index to every table, unless there is a valid reason not to, like the table has few rows.

  • Seeks shown in Query/Execution plans for SELECT statements are good for performance, while scans should be avoided.

  • A table's size (number of rows) is also a major factor used up by Query Optimizer when determining best query plan.

  • Index order plays an important role in many query plans. For example, in the authors table of the pubs database, a non-clustered index is defined in the order of au_lname, then au_fname.


    Fine Query A

    SELECT * FROM authors WHERE au_lname like 'r%'

    This uses a Bookmark Lookup and an Index seek.

     

    Fine Query B

    select * FROM authors WHERE au_lname LIKE 'r%' AND au_fname like ‘a’

    This uses a Bookmark Lookup and an Index Seek.

     

    Not so Fine Query C

    SELECT * FROM authors WHERE au_fname LIKE ‘a’

    This uses a Clustered Index Scan.

  • SQL Server 2000 (not earlier versions) offers both ascending and descending sort orders to be specified in an index. This can be useful for queries, which uses the ORDER BY DESC clause.

  • To find a particular word (for e.g. a table name) used in all stored procedure code, you can use the following code to identify it. For example, you can use this to find out a list of SP’s using a table.

    SELECT DISTINCT a.name AS SPName FROM syscomments b, sysobjects a

    WHERE b.text LIKE '%authors%' AND a.id=b.id AND a.type='P'

This query brings all SP’s having text “authors” in their code. Note that this query might bring extra SP’s, for example, if a stored procedure uses text in a comment.

 

Step Two: What to Do Once You Have Gathered the Necessary Information

Actions for Key Tables

For static tables (tables that rarely, if ever change), you can be liberal on the number of indexes that can be added. As mentioned earlier, too many indexes can degrade the performance of highly transactional tables, but this does not apply to tables whose data will not change. The only consideration possible could be disk space. Set all index fill factors on static tables to 100 in order to minimize disk I/O for even better performance.

For highly transactional tables, try to limit the number of indexes. Always keep in mind that a non-clustered index contains the clustered index key. Because of this, limit the number of columns on your clustered index in order to keep their size small. Any index for busy transactional tables has to be highly justifiable. Choose the fill factor with caution (usually 80 to 90%) for these indexes in order to avoid potential page splitting.

For tables used lot in stored procedures/embedded SQL, these tables play an important role in the total application lifetime as they are called most often. So they require special attention. What is important is look at how tables are being accessed in queries in order to eliminate scans and convert them into seeks. Watch the logical I/O used by "Set Statistics IO on" to help you determine which queries are accessing the most data. Less logical I/O is better than more. Choose clustered index with caution. Depending on how transactional the table is, choose a higher fill factor.

For tables with index size greater then data size implies a lot of indexes, so review indexes and make sure their existence is useful and justified.

For the Top 10 or 15 largest tables, keep this fact in mind when creating indexes for these types of tables, as their indexes will also be large. Also check to see if the tables are static or non-static, which is helpful information when deciding what columns need to be indexed.

For the most frequently called Stored procedures/Embedded SQL, See the Query plans and Logical I/O page use.

SQL Profiler Trace is a very good tool. It tracks calls getting executed in SQL Server at any given point of time, their execution time, I/O reads, user logins, executing SQL statement, etc. It can also be used as debugging tool. An analysis of a Profiler trace is important to identify slow running queries. You can set the duration to > 100ms to see queries which take more then 100 milliseconds to execute.

 

Using a Covering Index + Non-clustered Index Uses Clustered Index as a Row Locator

One can leverage the fact that non-clustered indexes store clustered index keys as their row locators. Meaning that a non-clustered index can behave as a clustered index if the index has all of the columns referenced in SELECT list, WHERE clause, and JOIN conditions of a query.

Example 1

In the Orders table the NorthWind database, there currently is a non-clustered index on the ShippedDate column.

Try running the following:

SELECT ShippedDate, shipcity FROM orders WHERE ShippedDate > '8/6/1996'

The query plan of statement produces a Clustered Index Scan.

Now add the column shipcity to the non-clustered index on ShippedDate.

CREATE INDEX [ShippedDate] ON [dbo].[Orders] ([ShippedDate], [ShipCity]) WITH DROP_EXISTING

Now run the query again. This time, the query plan of statement produces an Index Seek.

This magic happened because all fields (ShippedDate and ShipCity) in the SELECT and the WHERE clauses are part of an index.

Example 2

In the Titles table of the Pubs database, check out the following execution plan for this query:

SELECT title_id, title FROM titles WHERE title LIKE 't%'

Notice that the execution plan shows an Index Seek, not a Bookmark Lookup (which is what you usually find with a non-clustered index). This is because the non-clustered index on the Title column contains a clustered index key Title_Id, and this SELECT has only Title_Id, Title in the SELECT and in the WHERE clause.

 

Now the Hard Part Starts

By following the simple steps outlined here, you get useful pieces of information in no time that can help you improve the performance of your database. After you have data in front of you put it to work. These minor inputs will bring a majority of your results.

 

Published with express written permission of the author. Copyright 2002.

'programming > MSSQL' 카테고리의 다른 글

[Tip]mdf파일 만으로 DB 복구하는 방법  (0) 2003.11.12
[튜닝] index...  (0) 2003.10.14
SQL Server에서 Blocking을 줄이기 위한 전략!!  (4) 2003.10.06

태국쪽 DB서버의 CPU사용량이 갑자기 증가되어 그 원인을 찾던 중...

그 문제가 index에 있는것을 알았다.

헐... 데이터라고는 고작 12000row 정도 밖에 없는 테이블인데...

 

그 테이블에 인덱스가 없다고.. cpu사용량이 70%까지 올라갔다가..

index하나 만들어주니 20%이하로 줄다니...

 

하여간 항상 index를 제일 먼저봐야겠다는 생각을 다시 한번 했다.

 

출처 : http://www.sql-server-performance.com

읽어보시면 알겠지만, 많은 도움이 됩니다.
영어를 잘 못하는 관계로 해석 되는거 같은 부분만 번역 달아 놓겠습니다. 혹시 틀린 부분이 있으면 답글 부탁드립니다. 바로 정정하겠습니다.
번역 안되어 있는 부분 번역해 주시면 바로 원문에 반영하겠습니다.

Strategies to Reduce SQL Server Blocking
(SQL Server Blocking을 줄이기 위한 전략)

by Sancho Fock

No reasonable strategy for the resolution of SQL Server blocking problems can be found until one has determined the precise nature of the block. The most obvious criterion for distinguishing between different blocking issues is their average duration.
The following categories emerge as a result of this division:

Short-time Blocking: Average duration less than three seconds.
(짧은 시간 블러킹 : 평균 3초 이하의 수행 시간을 갖는 트랜잭션)

Mid-time Blocking: Average duration ranges from 3 seconds to a maximum of 10 minutes.
(중간 시간 블러킹 : 평균 3초 ~ 10분 이하의 수행 시간을 갖는 트랜잭션)

Long-time Blocking: Average duration more than 10 minutes.
(긴 시간 블러킹 : 10분 이상의 수행 시간을 갖는 트랜잭션)

Deadlocks: In theory, there is no limit to the duration, and because of this, SQL Server automatically terminates one of the blocked processes.
These four different types of blocks are discussed below in terms of their possible causes and in reference to the appropriate strategies for resolving them.


Short-Time Blocking
(짧은 시간 블러킹)

Short-term blocking is inevitable in multi-user databases.
(짧은 시간의 블러킹은 다중 사용자 데이터베이스에서는 피할 수 없다.)
Normally, they represent no problem for the operation of an application.
Nevertheless, these types of blocks should be investigated in cases where they have begun to occur to only a few users or where they occur very frequently.
(그렇지만, 사용자가 적을때 발생하거나, 매우 자주 발생한다면 원인을 찾아야한다.)
If these blocks appear frequently, it can lead to a snowball effect and eventually paralyze the entire system.
(만약 블러킹이 매우 자주 발생된다면, snowball 효과로 인하여 (이게 뭔지 아시는 분 ^^;;) 전체 시스템의 마비를 가져오게 된다.)

Even in cases where it is likely that the problem cannot be completely solved, one should nevertheless at least attempt to defuse it.


Causes of Short-Term Blocking
(짧은 시간의 블럭킹이 발생하는 원인)

Short-time blocking, which occur very frequently, can be traced back to the following basic problem: the total performance capacity of the system is not enough for the current user load.
(짧은 시간의 블러킹은 다음과 같은 일반적인 문제로 인해 매우 빈번히 발생된다. : 시스템이 현재 전체 사용자의 부하를 견디지 못하는 경우.)

Resolution Strategies for Short-Term Blocking
(짧은 시간의 블러킹 해결 방안)

Such problems can best be met by carrying out an extensive performance tuning of the server and of the application. If this situation does not occur until there is a very high user load, then one should begin the investigation by examining the server and the network.

However, if this situation begins to occur with low user load levels, then one should investigate whether certain use cases of the client application are able to block one another or even themselves in conceptual terms. If this should be found to be the case, then an investigation needs to be carried out to determine whether the probability of the occurrence of this unwanted situation can be reduced through atomic transactions or the use of "row-level locking" or similar strategies.



Mid-Time Blocking
(중간 시간 블러킹)

This type of scale block is the most difficult to find.
(이 정도 크기의 블럭은 가장 찾기 힘든 경우이다.)

It lasts long enough to bring the operation of an application to a stop, but at the same time is still generally too short for manual analysis.
Support for this ability is available with THS Software's SQL Guard 2000. A demo version of SQL Guard 2000 can be downloaded free-of-charge from www.thsfock.de.


Causes of Mid-Time Blocking
(중간 시간 블러킹의 원인)

The possible causes for this type of block are the following:

(이런 종류의 블러킹의 원인이 될만한 것들은 아래와 같다.)

- Transactions which are (too) complex.
(트랜잭션이 매우 복잡한 경우)

- Extremely important interrogations in a transaction.

- Non-error-free interrogations in transactions (e.g. unintended cross-joins).

- User interaction within transactions (e.g. message box "Should data really be deleted?").
(트랜잭션 내의 사용자 interaction(예를들면 '이 데이터를 지우겠습니까?'라는 메세지 박스)

- Unnecessarily time-consuming processing within transactions.

- Unnecessarily distributed processing with high data transport volumes.
(불필요한 많은 양의 데이터를 분산 처리하는 일)

- Snowball effect of short-time scale blocks.

Resolution Strategies for Mid-Time Blocking

(중간 시간 블럭킹의 해결 방안)

Once one has established which transactions are blocking other processes ? e.g. with the help of SQL Guard ? a determination must be made as to which type of error is present.

The following questions emerge in cases of complex transactions:

- Can the transaction be simplified?
(트랜잭션을 보다 간단하게 만들 수 있는가?)

- Can the transaction be divided up into smaller parts?
(트랜잭션을 작은 부분들로 나눌 수 있는가?)

- Can the transaction be greatly accelerated through performance optimization?
- Can the transaction be carried out at a later time (e.g. a nighttime job)?
- Could the transaction also use separate resources (e.g. temporary tables) in order to carry out the actual modifications in concentrated fashion if successful?
- Can the data transport within the transaction be reduced (e.g. swapping processing out into SP's)?
- Does the transaction block resources unnecessarily (e.g. a SELECT which locks lookup tables)?

These questions offer approaches for solving the problem. Should it happen that all of the questions are to be answered in the negative, then one is faced with the choice of either accepting the situation as it is, or of thinking through the business processes to find a way to replace the problematic transactions with others as necessary.



Additional Mid-Time Resolution Strategies
(추가적인 중간 시간 트랜잭션의 블러킹 해결 전략)

If the transaction involves extremely important interrogations, replace them with faster ones.


If user interactions ? such as message boxes ? take place during database transactions, then these must be eliminated! User interactions have lost absolutely nothing within database transactions. Make sure without fail that your client programmers are also aware of this. Programmers with a background in desktop database development are particularly susceptible to having frequent problems distinguishing between business transactions and database transactions.


The same holds true for unnecessarily time-consuming processing within the transaction as much it does for more complex transactions. You could however also ask yourself the question, "Does this processing really have to take place within the transaction?"


In cases where a large amount of data is transported from the server to the client within a transaction, this should be minimized where possible. The processing of x-amount of data is fundamentally just as fast at the client end as it as on the server. The bottleneck is as a rule the transport through the network. Therefore, always carry out the processing at the place where most of the necessary information is to be found. For example: if one needs only to know the total number of certain types of data sets (and not to have the data sets themselves), then using a "select count(*)" will always be faster than even the most wonderful algorithm at the client end (because the client first needs to obtain all the data via the network). If, on the other hand, an SP requires kilobytes of parameters, then the client may be considerably faster.


If a snowball effect is present, then follow the strategies used against short-time scale blocks.


Long-time Blocking
(장시간의 블러킹)


These blocks are very similar to mid-time scale blocks. As a general principle, they can also have the same causes as the mid-time scale blocks.
이런 블러킹은 중간 시간 정도의 블러킹과 매우 유사하다. 일반적인 이론에 의하면, 이런 장시간 블러킹의 원인은  중간 시간 정도의 블러킹 원인과 같다.)

 

In addition, they can have the following causes:
(추가적으로 아래와 같은 것들이 원인일 수도 있다.)


Unintentionally non-closed transactions, and Endless loops within transactions

(실수로 transaction을 종료하지 않는 경우나 트랜잭션 안의 무한루프)


The following applies to both causes: their durations could fall within the mid-time scale block range if, for example, transaction timeouts have been defined or if the end user shuts down his client.


Resolution strategy for Log-Time Blocking

(장시간 블러킹 해결 방안)

The resolution strategy for both of the additional causes is clear: eliminate the error(s).
(추가적인 두가지 원인의 해결 방안은 확실하다 : 에러를 없애라)


The Special Case of Deadlocks
(데드락의 특별한 경우)


In view of the fact that a great deal of information concerning deadlocks is readily available in the relevant literature, they will be treated only briefly here: deadlocks are a special case in terms of scale blocks, because there is no unambiguously "guilty party" in such situations.

SQL Server is also very adept at recognizing and treating deadlocks, as you will find when you read the SQL Server documentation. Essentially, SQL Server does the same thing against deadlocks that the SQL Guard 2000 does against blocks: it terminates a process. The only difference is that the SQL Server recognizes no guilty party when faced with a deadlock, and therefore selects a "victim".

One can never completely exclude deadlocks from larger systems. The strategies used to reduce their quantity are the same as those that can be used to avoid blocks in general. In addition, one can take care to ensure that there are no transactions present which require the same resources in the reverse order.



A Summary of the General Strategies
and Guidelines for Reducing SQL Server Blocking
(SQL 서버의 블러킹을 줄이기 위한 일반적인 전략과 가이드 라인)

* Forbid user interactions in transactions.
(트랜잭션 안에 사용자와의 interaction(입력을 기다린다던가 하는 작업)을 금한다.)

* Always keep transactions as limited in size and as brief as possible.
(트랜잭션은 항상 가능한 한 짧은 시간동안 최소한의 범위를 유지해야 한다.)

* Use no unnecessary resources in transactions.
(트랜잭션 안에서는 불필요한 리소스는 사용하지 않는다.)

* Carry out as little external processing as possible during a transaction.

* Always select with the option "with no locks" except in cases where you have an important reason for doing otherwise.

(다른 중요한 이유로 뭔가를 수행하는 경우가 아니라면, 항상 SELECT 구문에 'with no locks' 옵션을 사용하라.)


* Use row level locking.
(row단위 락킹을 사용한다. 예를 들면 from tableName WITH (NOLOCK)과 같이)

* Use "dirty reads" wherever possible (never make this option global, because it is not possible except with only a very few interrogations).

(가능하면 'dirty reads'를 이용하라


* Performance tune your systems as much as possible.
(가능한 한 많은 시스템 성능 튜닝을 한다.- 당연한 얘기 --;;)

* Carry out necessary complex transactions such as invoicing at times when the user load is as low as possible.

* Schedule maintenance tasks which put extra loads on the server (e.g. Full Backup, defragmentation of indexes) at times when the user load is minimal (nights, weekends)
(서버에 추가적인 부하를 주는 maintenance task(예를 들면, DB Full Backup, index 조각모음)의 스케쥴은 서버의 부하가 최소인 시간으로 잡는다.

* Always select as little as possible and only as much as is necessary.
(가능한한 적은 row만을 Select하고, 꼭 필요한 만큼만 Select한다.)

Sancho Fock has been a freelance software developer since 1995. His professional area of concentration is the object-oriented software development of applications using two or more layers. In his numerous projects he has accumulated experience with various RDBM's such as MS-SQL Server, Sybase Adaptive Server and Informix. He has had intensive experience with MS-SQL Server in Versions 6.5, 7.x and 8.x (2000). He has become familiar with MS-SQL Server in his various roles as a T-SQL developer, an applications developer and as a database administrator. Contact him at: sancho@thsfock.de Visit his website at: www.thsfock.de.

Published with the express written permission of the author. Copyright 2003.

'programming > MSSQL' 카테고리의 다른 글

[튜닝] index...  (0) 2003.10.14
VB프로그래밍 시 DB서버에 접속이 안되는 경우  (0) 2003.07.28
SQL 서버 이름을 바꾸고 시플땐~  (0) 2003.07.28
Set cnn1 = New ADODB.Connection
cnn1.Provider = "sqloledb"
cnn1.Open "Data Source=210.102.25.102;Initial Catalog=pubs;Network Library=dbmssocn;", "sa", ""


일반적으로 Connection String에 Network Library를 명시하지 않는데... 그것이 문제였다.

명시하지 않으면 Named Pipes를 사용하여 서버에 연결하거든!

dbnmpntw - Win32 Named Pipes
dbmssocn - Win32 Winsock TCP/IP
sp_dropserver old_server_name
exec sp_addserver new_server_name, local
go

라고 하시거나..
더 속편하게.. SQL서버7 시디를 넣고 setup을 돌리시면?
이를 다시 보정해 줍니다.(DB는 이상 없지요)


아울러 EM은 클라이언트 툴입니다.
새롬 데이터맨을 삭제해도 하이텔은 돌아 가는것과 마찬가지 이지요.
EM에서 delete레지스트레이션 하신후 다시 등록 하시면?
잘 되실 겁니다.

그럼 이만.

간단합니다.

regrebld Utility
Use the regrebld utility to back up or restore the Microsoft SQL
Server registry entries if they become corrupted.

regrebld -restore
하심 바로 해결 됩니다.
참고로 NT를 재설치 했을때도 역시 유용 합니다.
서버 이름이 빠뀜도 역시 마찬가지 입니다.
그럼 이만.
Trigger가 걸려있는 테이블에 Insert한 후 @@IDENTITY를 하면 Trigger가 걸린 테이블이 ID컬럼을 갖는 경우 @@IDENTITY값이 틀릴 수 있다. 그러므로 아래와 같은 문장을 이용할 것

IDENT_CURRENT('table_name')
DBCC CHECKIDENT (tblChargeCardDepositTemp , RESEED , 0)

+ Recent posts