SQL Server 2005 버전 부터 기존 Native 확장프로시저의 개념으로 .net 환경의 CLR 코드의 통합을 제공한다

기본 네이티브 확장프로시저는의 문제점은 위험한 코드로 인해 SQL Server 자체의 보안이나 실행에 영향을 줄수 있다는것인데 2005 부터 지원되는 CLR의 경우 SQL Server와 실행의 완벽한 분리로 리스크를 최소한으로 줄였다고 한다.


이번에 SQL Server 암호화 모듈을 위해 Native 확장프로시저및 CLR 코드로 만들어 비교해 봤는데 CLR 의 압승이었다

Native의 경우 crypto++ 이라는 라이브러리로 래핑을 하였고 CLR의 경우 System.Security.Cryptography 의 라이브러리를 사용해서 만들었다.

대강의 느낌은 CLR 쪽이 3배 이상 빠른것으로 판단이되며 추측키로는 C++의 경우 확장프로시저 내의 객체 인스턴스 메모리의 할당하는 부분에서 승패를 가르지 않았는가 생각이 들지만 확인은 못해봤다.
아니면 알고리즘 구현 자체에 품질 문제 일수도 있을테고...

어찌 되었던 원래의 목적인 다중키 관리를 위해 키 저장소가 필요했고 키 저장소를 위해 xml 파일등 보다는 레지스트리에 저장을 하는것이 바이너리저장및 나름의 이점이 있지 않을까 생각이 들었고, 간단한 WinForm 을 제작하여 테스트를 해보았을때도 문제가 없었다.

그리고 CLR로 올리고 테스트 하는순간 레지스트리 접근을 못한다는것을 알았다

이유인 즉..
디폴트로 SQL Server CLR를 배포했을 경우 권한 수준이 "안전"(SAFE)수준으로 배포가 되어 SQL Server 이외의 리소스에 대해서 접근이 안됐다.

그래서 권한 수준을 "외부"나 "안전하지 않음"으로 배포를 해야 한는데 배포를 하면 다음과 같은 에러가 발생한다.

오류: 어셈블리 'IntCryptNetProc'에 PERMISSION_SET = EXTERNAL_ACCESS에 대한 권한이 없으므로 어셈블리 'IntCryptNetProc'에 대한 CREATE ASSEMBLY가 실패했습니다. 어셈블리는 DBO(데이터베이스 소유자)에게 EXTERNAL ACCESS ASSEMBLY 권한이 있고 데이터베이스에 TRUSTWORTHY 데이터베이스 속성이 있는 경우 또는 어셈블리가 현재 인증서로 서명되어 있거나 EXTERNAL ACCESS ASSEMBLY 권한이 있는 관련 로그인을 소유한 비대칭 키로 서명되어 있는 경우에 권한이 부여됩니다. 이 데이터베이스를 복원하거나 연결한 경우 데이터베이스 소유자가 이 서버의 올바른 로그인에 매핑되어 있는지 확인하십시오. 그렇지 않으면 sp_changedbowner를 사용하여 문제를 해결하십시오.

결론은 "권한이 있는 계정"으로 "TRUSTWORTHY 데이터 베이스 속성"이 되어있는 Database 에만 "외부"나 "안전하지 않음"의 권한 수준을 가지는 CLR를 배포할수 있다.

권한있는 계정은 sa나 그에 상응한는 계정으로 처리하면 되고 TRUSTWORTHY 데이터 베이스 속성은 아래와 같이 만들면 된다.

ALTER DATABASE SecureDB SET TRUSTWORTHY ON;



이번 CLR을 테스트 해보면서 거듭 느낀점은 .net 코드도 충분히 쓸만하게 성능이 나온다는것이다
경우에 따라서는 기존 native 보다 더 좋은 성능이 나오는것에 대해서 당황(?)을 하기도 하지만.. ^^


참고 :
http://technet.microsoft.com/ko-kr/library/ms345101.aspx
http://technet.microsoft.com/ko-kr/library/ms187861.aspx
http://msdn.microsoft.com/en-us/library/ms189524.aspx


ps.
위에 사항을 해결하기 위해 RegistryPermission 라는 클래스를 많이 찾아보았는다. (삽질..)
물론 직접적인 도움이 되지는 않았지만 먼가가 새로운 세계가 있는 갑다. 흐흐..

'Dev > SQL' 카테고리의 다른 글

How to Configure MSDTC to Use a Specific Port in Windows Server 2012/2012R2  (0) 2014.07.03
CTE (Common Table Expression)  (0) 2008.07.08
테이블 변수  (0) 2008.07.04

IDispatch* GetDispatchPtr(VARIANT &var)
{
    VARIANT *pvar = &var;
    IDispatch* pdisp = NULL;

    if (var.vt == (VT_BYREF | VT_VARIANT)) {              // 1
        pvar = var.pvarVal;
    }

    if (pvar->vt == (VT_BYREF | VT_DISPATCH)) {           // 2
        pdisp = *pvar->ppdispVal;
    }
    else if (pvar->vt == VT_DISPATCH) {                   // 3
        pdisp = pvar->pdispVal;
    }

    return pdisp;
}

ex)
ADODB::_RecordsetPtr sp(GetDispatchPtr(var));



VB에서 Host 객체를 Early Binding 으로 호출 (컴포넌트를 참조한후 실행할 때..)
=> 3번만 호출

VB에서 Host 객체를 Late Binding 으로 호출 (CreateObejct 사용..)
=> 2번만 호출

VBScript 에서 Host 객체를 Late Binding 으로 호출 (VBScript 에서는 Late Binding만 지원)
=> 1번, 3번 호출

 

'Dev > Windows' 카테고리의 다른 글

ATL Com Project VC++ 6 에서 VC++ 8 변환(업그레이드)  (0) 2009.03.27
유니코드(UNICODE), C++  (0) 2008.10.16
ffmpeg  (0) 2008.04.09
벤치마킹  (0) 2007.10.17
달라진 기능 (IIS 6.0)  (0) 2007.09.28

http://msdn.microsoft.com/en-us/library/bb978523.aspx
http://msdn.microsoft.com/en-us/library/bb735856.aspx


WCF의 COM+ 통합서비스

쉽게 얘기해서 COM+의 서비스를 종전의 DCOM이나 RDS처럼 WCF 여러 채널(바인딩)을 통해서 서비스 하는 방법이다

Binding

Interoperability

Transactions

Encoding

BasicHttpBinding

Basic Profile 1.1

(None)

Text, (MTOM)

WSHttpBinding

WS

(None), Yes

Text, (MTOM)

WSDualHttpBinding

WS

(None), Yes

Text, (MTOM)

WSFederationHttpBinding

WS-Federation

(None), Yes

Text, (MTOM)

NetTcpBinding

.NET

(None), Yes

Binary

NetNamedPipeBinding

.NET

(None), Yes

Binary

NetMsmqBinding

.NET

(None), Yes

 

NetPeerTcpBinding

Peer

(None)

 

MsmqIntegrationBinding

MSMQ

(None), Yes

 


여기서 WSHttpBinding과 BasicHttpBinding 과 같은 경우는 IIS를 통해서 지원을 하고,
NetTCPBinding 과 같은 경우는 COM+를 통해서 호스팅이 가능 하도록 설계되어 있다
물론 WAS(IIS 7.0)의 경우 모두 호스팅이 가능할 것으로..
(COM+ 통합의 경우 셀프 호스팅은 아직 안해봐서 모르겠다..)



WCF의 COM+ 통합서비스를 하려면 다음과 같은 도구가 필요하다

- .NET Framework 3.0 (or 3.5 ) (3.5를 설치하면 3.0, 2.0 등이 모두 설치된다.) - 3.5 권장..
- SvcConfigEditor.exe (Service Configuration Editor) 혹은 ComSvcConfig.exe

ComSvcConfig.exe는 .NET Framework 3.0와 함께 제공되며 커맨트 툴로 COM+의 WCF의 구성을 돕는다.
허나 .NET SDK로 제공되는  SvcConfigEditor.exe를 이용하면 Visual 한 환경으로 WCF 구성파일 편집, 생성및 COM+을 쉽게 구성할수 있다.

* ComSvcConfig.exe : http://msdn.microsoft.com/ko-kr/library/ms732009.aspx



구성 방법

1. 우선 만들어진 컴포넌트(VC++ ATL 간단하게 만들었다)를 COM+에 패키지를 생성하여 추가한다.

2. SvcConfigEditor.exe를 실행하여 "파일->통합->COM+응용프로그램" 메뉴를 선택
- COM+의 패키지의 컴포넌트 인터페이스를 선택
- 컴포넌트의 메서드 선택
- COM+ 호스팅 선택
- TCP를 선택
- 서비스 주소 세팅 (ex: net.tcp://localhost:9000/Simple)
- 완료

3. 2번과 같이 세팅이 완료된 경우 COM+의 해당 패키지의 등록정보-활성화 탭의 "응용 프로그램 루트 디렉토리"란에 WCF 설정파일이 생성된 디렉토리 경로가 세팅된다.
ex: C:\Program Files\ComPlus Applications\{593add39-f66f-442a-a901-01379dbac4eb}\

4. 그리고 netstat 로 확인을 해보면 hosting 이 되어 있는걸 확인할 수 있다.

C:\>netstat -an | findstr 9000
  TCP    0.0.0.0:9000           0.0.0.0:0              LISTENING


위의 방법 이외에 웹호스팅으로도 선택하여 IIS를 통하여 서비스 하는것도 가능하며,
웹호스팅의 경우 웹사이트및 가상디렉토리를 선택하면 해당 디렉토리에 WCF구성파일을 생성해준다
(.svc 과 web.config)



테스트

위와같이 세팅이 되어 있다면 Visual Studio 2005 (Extensions for WPF and WCF 설치)나 Visual Studio 2008을 이용하여 테스트 가능하다

SvcUtil.exe 과 같은 툴로 스켈레톤 코드를 생성하여 포함시켜 사용해도 되고 VS 2008의 경우 서비스 참조를 하면 자동으로 생성을 해준다.

그리고 참조된 객체를 생성할때 생성자의 파라미터로 app.config에 설정되어 있는 endpoint 중에 하나를 선택하여 그 이름을 세팅하면 해당 endpoint를 이용하여 Communicaiton(통신)를 하게 된다.

using (Simple.SimpleClient s = new Simple.SimpleClient("NetTcpBinding_ISimple"))
{
    int nResult = (int)s.Add(50, 58);
    Console.WriteLine("result = {0}", nResult);
}


그러나 처음 실행하면 다음과 같은 오류를 뱉어낸다.

통신 개체 System.ServiceModel.Channels.ServiceChannel은(는) Faulted 상태이기 때
문에 통신에 사용할 수 없습니다.

이유는 COM+의 해당 패키지를 호스팅하는 프로세스가 객체를 자동 활성화 시키지 못해서 그런것 같다.
그러나 이미 활성화가 되어 있는 경우는 문제 없다.
어떻게 활성화를 자동으로 시킬지는 알아봐야 할듯...

* 이벤트로그 내용

COM+: COM 인스턴스를 만드는 동안 오류가 발생했습니다.
 원본:
 App ID: 593add39-f66f-442a-a901-01379dbac4eb
 CLSID: 9833d2b6-d279-4bc3-b9be-7a4194c4a1b2
 들어오는 트랜잭션 ID: 00000000-0000-0000-0000-000000000000
 서로게이트: CDECL-DESK\cdecl
 요청 ID: System.Runtime.InteropServices.COMException (0x80070542): 적어도 클라이언트 토큰은 Out of process Webhost 활성화를 위한 최소 가장의 SecurityImpersonationLevel을 갖고 있어야 합니다.
   위치: System.ServiceModel.ComIntegration.ComPlusInstanceProvider.GetInstance(InstanceContext instanceContext, Message message)
 예외: aspnet_wp
 프로세스 이름: 22228
 프로세스 ID: %9



위의 이유에서인지 MS에서는 WCF 서비스 형태로도 제공되는 COM+의 경우 해당 패키지를 서비스 형태로 실행하는 방법에 대해서 제시를 한다.

     서비스 COM+ 패키지 -> 등록정보 -> 활성화 탭 ->  "NT서비스로 응용프로그램 실행"

서비스 형태로 등록을 한 후 해당 패키지를 중지->시작 을 하면 서비스 형태로 실행이 되어 시스템 재시작 후에도 문제가 없다고 하는데...


기타

WCF의 COM+ 통합서비스를 하기 위해서는 XP및 Windows 2003 서버에 아래의 업데이트를 설치를 해줘야 한다.

Windows Communication Foundation용 업데이트(KB912817)

간략한 설명 :
MSDTC의 WS-AtomicTransaction 프로토콜에 대한 지원과 WCF(Windows Communication Foundation) COM+ 통합 기능에 대한 지원을 추가합니다.


'Dev > .NET' 카테고리의 다른 글

SerializeToXML - C#  (0) 2009.08.10
C# Web Service -> REST  (0) 2009.08.09
Interop 응용 프로그램 배포  (0) 2007.10.05
RCW, CCW  (0) 2007.10.04
"The underlying connection was closed" - WebServices  (0) 2005.10.13

'Dev' 카테고리의 다른 글

Visual Studio Code, Python 개발환경 구축  (0) 2020.01.27
요즘, 단상..  (0) 2006.03.28
Subversion 아직은...  (0) 2004.12.06
공익 광고 ..  (0) 2004.11.29
버전관리툴  (0) 2004.11.24
http://sourceforge.net/projects/asio/

asio is a cross-platform C++ library for network and low-level I/O programming that provides developers with a consistent asynchronous model using a modern C++ approach.


asio 는 클로스 플랫폼은 지원하는 네트워크 라이브러리이다

ACE와는 비교도 안되게 가볍고 C++ 헤더로만 이루어져 있어 별도의 라이브러리 컴파일 과정이 필요없다.
그리고 각 플랫폼에 맞는 동기/비동기 모델을 하나의 인터페이스로 구현을 하여 유연성있는 네트워크 프로그램을 제공을 한다

boost 1.35부터 포함되어 있어 boost 라이브러리를 통해서 사용가능하고 직접 다운받아 stand alone 으로도  사용 가능하다


Download 쪽 항목을 보면 asio-tr2 라고 하는 패키지가 보이는데,
C++ tr2의 네트워크 라이브러리에 대한 제안서로 보인다.

개인적으로 tr2에 정의되어 있는 네트워크 라이브러리의 C++ 구현 인터페이스가 무지 궁금하지만,
asio 를 채택하는것도 그리 나쁜 선택은 아니라고 판단된다.


ps.
tr2의 내용중에 XML, HTML, Networking 같은 경우는 boost와 같이 C++ 계에서 주도적(?)으로
사용되는 것이 없어서 어떤 것들이 채택(혹은 구현)될지 궁금하다.

tr2의 주 내용
Unicode
XML and HTML
Networking
Usability for novices and occasional programmers


'Dev > C++' 카테고리의 다른 글

C++ Refactoring  (0) 2009.04.14
An Overview of the Coming C++ (C++0x) Standard  (0) 2008.12.29
C++ 0x - Herb Sutter의 블로그 글  (0) 2008.07.29
C++ 0x  (0) 2008.05.09
memory pooling - code  (0) 2008.05.01

Herb Sutter 블로그의 C++ 0x 에 대한 리포트 링크 정리
http://herbsutter.wordpress.com/



http://herbsutter.wordpress.com/2007/05/10/trip-report-april-2007-iso-c-standards-meeting/

- 템플릿 별칭(aliase), 가변 템플릿 파라미터, using 용법 확장에 대한 내용들


http://herbsutter.wordpress.com/2007/09/10/trip-report-july-2007-iso-c-standards-meeting/

- 새로 추가되는 기능들에 대한 내용들
- constexpr, decltype  등...


http://herbsutter.wordpress.com/2007/11/01/trip-report-october-2007-iso-c-standards-meeting/

- C++ 0x 의 시기와 주요 컨셉에 관한 글
- nullptr 에 대한 소개
- threading, Concurrency, Atomic 에 관한 내용들


http://herbsutter.wordpress.com/2008/03/29/trip-report-februarymarch-2008-iso-c-standards-meeting/

- Lambda function and closure 에 관한 내용들


http://herbsutter.wordpress.com/2008/07/04/trip-report-june-2008-iso-c-standards-meeting/

- 초기화에 관한 내용들
- STL에서의 배열 초기화나 클래스 멤버의 초기화 문법에서의 초기화에 관한 이야기

'Dev > C++' 카테고리의 다른 글

An Overview of the Coming C++ (C++0x) Standard  (0) 2008.12.29
asio C++ library  (0) 2008.08.22
C++ 0x  (0) 2008.05.09
memory pooling - code  (0) 2008.05.01
Is Derived - code  (0) 2008.05.01

출처 : http://thinkweb2.com/projects/prototype-checklist/


1
The wrong way:
document.getElementById('foo')
The right way:
$('foo')

Surprisingly some people actually don't know about this one ( including ~100KB file just to use Ajax.Request family )

2
The wrong way:
var woot = document.getElementById('bar').value
var woot = $('bar').value
The right way:
var woot = $F('bar')

Handy shortcut for reading a value of a form control

3
The wrong way: 
$('footer').style.height = '100px';
$('footer').style.background = '#ffc';	
The right way:
$('footer').setStyle({
	height: '100px',
	background: '#ffc'
})

Dreaming about IE behaving W3C way? Not happenning! (but second construct will make you forget about cross-browser glitches)

4
The wrong way:
$('coolestWidgetEver').innerHTML = 'some nifty content'
The right way:
$('coolestWidgetEver').update('some nifty content')

One of those simple ones yet quite often forgotten. Yes, I know they are almost the same but I want to see you doing THIS with the first one
(isn't chaining just cool?)

$('coolestWidgetEver').update('some nifty content').addClassName('highlight').next().hide()

5
The wrong way:
new Ajax.Request('ninja.php?weapon1=foo&weapon2=bar')
The right way:
new Ajax.Request('ninja.php', {
	parameters: {
		weapon1: 'foo',
		weapon2: 'bar'
	}
})

Cleaner and better structured parameters definition

6
The wrong way: 
new Ajax.Request('blah.php', {
	method: 'POST',
	asynchronous: true,
	contentType: 'application/x-www-form-urlencoded',
	encoding: 'UTF-8',
})
The right way:
new Ajax.Request('blah.php')

All of these options are in Ajax.Request by default! "method: 'POST'" happens to be on every second pastie page I've seen 
(Still don't believe in JS inheritance? You don't have to. Just take advantage of it)

7
The wrong way: 
Event.observe('myContainer', 'click', doSomeMagic)
The right way:
$('myContainer').observe('click', doSomeMagic)

This one is debatable but second way is more Object Oriented (well... sort of) and easier to chain (So decide for yourself)

8
The wrong way: 
$$('div.hidden').each(function(el){
	el.show();
})
The right way:
$$('div.hidden').invoke('show')

Here's a typical "each overuse". We have invoke for such things, folks! Sadly not many people know about it.

9
The wrong way: 
$$('div.collapsed').each(function(el){
	el.observe('click', expand);
})
The right way:
$$('div.collapsed').invoke('observe', 'click', expand)

Ha! Take this! Invoke can also be used for event handling when iterating over a collection of elements. It's really easy, isn't it?

10
The wrong way: 
$$('input.date').invoke('observe', 'focus', onFocus);
$$('input.date').invoke('observe', 'blur', onBlur);
The right way:
$$('input.date')
	.invoke('observe', 'focus', onFocus)
		.invoke('observe', 'blur', onBlur)

Somehow people tend to forget about "chaining nirvana". Don't like the way it looks? Think about saving some time by NOT invoking $$ twice!

11
The wrong way: 
$('productTable').innerHTML = 
	$('productTable').innerHTML + 
	'<tr><td>' + productId + ' '
	+ productName + '</td></tr><tr><td>' 
	+ productId + ' ' + productPrice + 
	'</td></tr>'
The right way:
var rowTemplate = new Template('<tr><td>#{id} #{name}</td></tr><tr><td>#{id} #{price}</td></tr>');
$('productTable').insert(
	rowTemplate.evaluate({
		id: productId,
		name: productName,
		price: productPrice
	}))
)

No I'm not kidding. This has been posted to #prototype and something was wrong with it (hmm... I wonder what)

출처 : http://technet.microsoft.com/ko-kr/library/ms190766.aspx


SQL Server 2005 온라인 설명서(2007년 9월)
공통 테이블 식 사용

CTE(공통 테이블 식)는 SELECT, INSERT, UPDATE, DELETE 또는 CREATE VIEW 문 하나의 실행 범위 내에서 정의되는 임시 결과 집합이라고 볼 수 있습니다. CTE는 개체로 저장되지 않고 쿼리 지속 시간 동안만 존재한다는 점에서 파생 테이블과 비슷합니다. 그러나 CTE는 파생 테이블과 달리 자체 참조가 가능하며 동일 쿼리에서 여러 번 참조될 수 있습니다.

CTE를 사용하여 다음을 수행할 수 있습니다.

  • 재귀 쿼리를 만들 수 있습니다. 자세한 내용은 공통 테이블 식을 사용하는 재귀 쿼리를 참조하십시오.
  • 일반적인 뷰 사용이 필요하지 않을 때, 즉 메타데이터에 정의를 저장할 필요가 없을 때 뷰를 대체할 수 있습니다.
  • 스칼라 하위 SELECT에서 파생된 열 또는 비결정적이거나 외부 액세스가 없는 함수를 기준으로 그룹화할 수 있습니다.
  • 동일 문에서 결과 테이블을 여러 번 참조할 수 있습니다.

CTE를 사용하면 가독성이 향상되고 복잡한 쿼리를 쉽게 유지 관리할 수 있는 이점이 있습니다. 쿼리를 개별적이고 단순한 논리적 구성 블록으로 나눌 수 있습니다. 그런 다음 이 단순한 블록을 사용하여 최종 결과 집합이 생성될 때까지 보다 복잡한 중간 CTE를 작성할 수 있습니다.

CTE는 함수, 저장 프로시저, 트리거 또는 뷰 같은 사용자 정의 루틴에서 정의될 수 있습니다.

CTE는 CTE를 나타내는 식 이름, 선택적인 열 목록 및 CTE를 정의하는 쿼리로 구성되어 있습니다. CTE를 정의한 후에는 SELECT, INSERT, UPDATE 또는 DELETE 문에서 테이블이나 뷰처럼 참조할 수 있습니다. CTE는 CREATE VIEW 문에서 정의하는 SELECT 문의 일부분으로 사용될 수도 있습니다.

CTE의 기본 구문 구조는 다음과 같습니다.

WITH expression_name [ ( column_name [,...n] ) ]

AS

( CTE_query_definition )

모든 결과 열에 대한 고유 이름이 쿼리 정의에 제공된 경우에만 열 이름 목록이 선택 사항입니다.

CTE를 실행하는 문은 다음과 같습니다.

SELECT <column_list>

FROM expression_name

다음 예에서는 CTE 구조의 구성 요소인 식 이름, 열 목록 및 쿼리를 보여 줍니다. CTE 식 Sales_CTE에는 3개의 열(SalesPersonID, NumberOfOrdersMaxDate)이 있으며 각 영업 사원의 SalesOrderHeader 테이블에 총 판매 주문 수 및 가장 최근의 판매 주문 날짜로 정의됩니다. 문이 실행될 때 영업 사원에 대해 선택한 열을 반환하기 위해 그리고 해당 영업 사원의 관리자에 대한 유사 세부 정보를 검색하기 위해 CTE가 두 번 참조됩니다. 영업 사원 및 관리자에 대한 데이터는 모두 단일 행으로 반환됩니다.

USE AdventureWorks;
GO
WITH Sales_CTE (SalesPersonID, NumberOfOrders, MaxDate)
AS
(
    SELECT SalesPersonID, COUNT(*), MAX(OrderDate)
    FROM Sales.SalesOrderHeader
    GROUP BY SalesPersonID
)
SELECT E.EmployeeID, OS.NumberOfOrders, OS.MaxDate,
    E.ManagerID, OM.NumberOfOrders, OM.MaxDate
FROM HumanResources.Employee AS E
    JOIN Sales_CTE AS OS
    ON E.EmployeeID = OS.SalesPersonID
    LEFT OUTER JOIN Sales_CTE AS OM
    ON E.ManagerID = OM.SalesPersonID
ORDER BY E.EmployeeID;
GO

다음은 결과 집합의 일부입니다.

EmployeeID  NumberOfOrders MaxDate  ManagerID NumberOfOrders MaxDate
----------- -------------- ---------- --------- -------------- ----------
268         48             2004-06-01 273       NULL           NULL
275         450            2004-06-01 268       48             2004-06-01
276         418            2004-06-01 268       48             2004-06-01
277         473            2004-06-01 268       48             2004-06-01

'Dev > SQL' 카테고리의 다른 글

How to Configure MSDTC to Use a Specific Port in Windows Server 2012/2012R2  (0) 2014.07.03
SQL Server CLR - 레지스트리 읽기  (0) 2008.10.10
테이블 변수  (0) 2008.07.04

INF: 질문과 대답 - SQL Server 2000 - 테이블 변수

기술 자료 ID : 305977
마지막 검토 : 2006년 11월 20일 월요일
수정 : 5.0

요약

이 문서에서는 SQL Server 2000에 소개된 테이블 변수와 관련된 질문과 대답(FAQ) 몇 가지를 제공합니다.

테이블 변수에 대한 SQL Server 온라인 설명서의 설명을 보려면 다음 Microsoft 웹 사이트를 방문하십시오.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_ta-tz_7ysl.asp (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tsqlref/ts_ta-tz_7ysl.asp)

추가 정보

질문 1: 임시 테이블을 이미 사용할 수 있는데 테이블 변수를 소개한 이유는 무엇입니까?

대답 1: 테이블 변수는 임시 테이블에 비해 다음과 같은 장점이 있습니다.
SQL Server 온라인 설명서의 "테이블" 문서에서 언급한 것처럼 로컬 변수 같은 테이블 변수에는 잘 정의된 범위가 있으며, 종료할 때 자동으로 정리됩니다.
테이블 변수는 임시 테이블에 비해 저장 프로시저(stored procedure)를 재컴파일하는 횟수가 적습니다.
테이블 변수가 포함된 트랜잭션은 테이블 변수의 업데이트 기간 동안만 지속됩니다. 따라서 테이블 변수에는 잠금과 로깅 리소스가 덜 필요합니다. 테이블 변수의 범위는 제한되어 있고 영구 데이터베이스의 일부가 아니기 때문에 트랜잭션 롤백의 영향을 받지 않습니다.
질문 2: 임시 테이블을 사용할 때보다 테이블 변수가 저장 프로시저를 재컴파일하는 횟수가 적다는 것은 무슨 뜻입니까?

대답 2: 다음 문서에서는 저장 프로시저를 재컴파일하는 몇 가지 이유를 설명합니다.

243586 (http://support.microsoft.com/kb/243586/) INF: 저장 프로시저(Stored Procedure) 재컴파일 문제 해결 방법
"임시 테이블 작업으로 인한 재컴파일" 절에서는 임시 테이블로 인한 재컴파일 같은 문제를 방지하는 몇 가지 요구 사항이 나열되어 있습니다. 이러한 제한은 테이블 변수에 적용되지 않습니다.

테이블 변수는 CREATE 또는 ALTER 문이 실행될 때 '재확인'이 발생하도록 만드는 배치에만 해당됩니다. 이것은 임시 테이블에 발생할 수 있습니다. 임시 테이블은 중첩된 저장 프로시저에서 테이블을 참조할 수 있도록 '재확인'할 필요가 있습니다. 테이블 변수는 저장 프로시저가 이미 컴파일된 계획을 사용할 수 있도록 이 과정을 완벽하게 피하므로 저장 프로시저를 처리할 리소스가 절약됩니다.

질문 3: 테이블 변수의 단점은 무엇입니까?

대답 3: 임시 변수와 비교하여 다음과 같은 몇 가지 단점이 있습니다.
PRIMARY 또는 UNIQUE 제약 조건을 위해 만든 시스템 인덱스 이외에 테이블 변수에는 클러스터되지 않은 색인을 만들 수 없습니다. 따라서 클러스터되지 않은 인덱스가 있는 임시 테이블과 비교할 때 쿼리 성능에 영향을 미칠 수 있습니다.
테이블 변수는 임시 테이블에서 할 수 있는 것처럼 통계를 유지하지 않습니다. 자동 만들기를 통해서나 CREATE STATISTICS 문을 사용하여 테이블 변수에 통계를 만들 수 없습니다. 따라서 큰 테이블에서 복잡한 쿼리를 수행하는 경우 통계가 없으면 최적화 프로그램이 쿼리를 위한 최적의 계획을 확인하는 것을 방해하여 해당 쿼리의 성능이 영향을 받을 수 있습니다.
초기 DECLARE 문 다음에 테이블 정의를 변경할 수 없습니다.
INSERT EXEC 또는 SELECT INTO 문에서 테이블 변수를 사용할 수 없습니다.
테이블 유형 선언에서 CHECK 제약 조건, DEFAULT 값 및 계산된 열은 사용자 정의 함수를 호출할 수 없습니다.
EXEC 문 또는 sp_executesql 저장 프로시저 외부에서 테이블 변수를 만든 경우 EXEC 문 또는 sp_executesql 저장 프로시저를 사용하여 테이블 변수를 참조하는 동적 SQL Server 쿼리를 실행할 수 없습니다. 테이블 변수는 로컬 범위에서만 참조할 수 있기 때문에 EXEC 문과 sp_executesql 저장 프로시저는 테이블 변수의 범위 밖에 있게 됩니다. 그러나 테이블 변수 로컬 범위가 EXEC 문이나 sp_executesql 저장 프로시저에 있기 때문에 EXEC 문이나 sp_executesql 저장 프로시저 내에서 테이블 변수를 만들고 모든 처리를 수행할 수 있습니다.
질문 4: 실제 디스크에 있는 데이터베이스에서 유지되기 때문에 임시 또는 영구 테이블에 비해 향상된 성능을 보장하는 테이블 변수 메모리 전용 구조가 있습니까?

대답 4: 테이블 변수는 메모리 전용 구조가 아닙니다. 테이블 변수에는 메모리에 저장할 수 있는 것보다 많은 데이터를 저장할 수 있기 때문에 디스크에 데이터를 저장할 위치가 있어야 합니다. 테이블 변수는 임시 테이블과 유사한 tempdb 데이터베이스에 만들어집니다. 메모리를 사용할 수 있는 경우 테이블 변수와 임시 테이블 모두 메모리에 만들어지고 처리됩니다(데이터 캐시).

질문 5: 임시 테이블 대신 테이블 변수를 사용해야 합니까?

대답 5: 대답은 다음 세 가지 요소에 따라 달라집니다.
테이블에 삽입된 행 수
쿼리가 저장된 재컴파일 수
쿼리 유형 및 성능에 대한 인덱스와 통계의 종속성
경우에 따라 임시 테이블이 있는 저장 프로시저를 작은 저장 프로시저로 나누면 재컴파일이 더 작은 단위로 발생하므로 유용합니다.

일반적으로 상당히 많은 양의 데이터가 있고 테이블 사용이 반복될 때를 제외하고는 가능하면 테이블 변수를 사용하는 것이 좋습니다. 이 경우 임시 테이블에 인덱스를 만들어 쿼리 성능을 높일 수 있습니다. 그러나 각 시나리오는 다를 수 있습니다. 테이블 변수가 특정 쿼리나 저장 프로시저에 대한 임시 테이블보다 유용한지 테스트하는 것이 좋습니다.

그래도 원하는 정보를 찾을 수 없으면 다음 Microsoft SQL Server 뉴스 그룹을 방문하십시오. Microsoft SQL Server 뉴스 그룹 (http://support.microsoft.com/newsgroups/)

이 문서나 다른 Microsoft SQL Server 기술 자료 문서에 대한 의견이 있으면 SQLKB@Microsoft.com (mailto:sqlkb@microsoft.com)으로 보내주시기 바랍니다.



Microsoft 제품 관련 기술 전문가들과 온라인으로 정보를 교환하시려면 Microsoft 뉴스 그룹 (http://support.microsoft.com/newsgroups/default.aspx)에 참여하시기 바랍니다.

차세대 C++ 표준인 C++ 0x 의 언어적인 추가 사항 정리
(C++ 1x 가 되지 않기를 빈다... ^^;)


- UTF-8, UTF-16 지원

= u8"I'm a UTF-8 string."
= u"This is a UTF-16 string."
= U"This is a UTF-32 string."


- Template Aliases

#include <vector>

template<typename T>
class MyAllocator {
};

template<typename T>
using MyVector = std::vector<T, MyAllocator<T>>;

MyVector<int> vec;


 - Allow sizeof to apply to non-static data members

Currently the C++ Standard does not allow the following:

struct S {
   int m;
};

sizeof(S::m)


- Generalized Constant Expressions - constexpr

아래의 코드처럼 작동하기 위해 추가된것 같다
이미 C 99 표준에서는 배열크기에 대해서 상수가 아닌 지역변수도 허용되는데 그것과는 또 다른 지원방식


constexpr int Number ()
{
    return 5;
}

double array[Number()];


constexpr int square(int x)
{
    return x * x;
}

float array[square(9)];  



- 중첩된 template 선언에서 >> 연산자의 문법오류

#include <vector>

// 현재의 경우 아래의 문법이 에러가 난다
// 이유는 마지막에 >> 부분이 중첩 tempate 문법의 닫는 의미가 아닌 시프트 연산자로 인식
// C++ 0x 버전에서는 문제없이 컴파일 될수 있도록 조치
typedef std::vector<std::vector<bool>> Flags;

// 그래서 아래와 같이 해야 했다
typedef std::vector<std::vector<bool> > Flags;


- auto 키워드 추가

컴파일 타임에 자동으로 타입을 유추하여 타입을 확정해주는 auto 라는 키워드 추가

for (vector<int>::const_iterator itr = myvec.begin(); itr != myvec.end(); ++itr) {} // 타입명시

for (auto itr = myvec.begin(); itr != myvec.end(); ++itr) {} // auto 사용


- stl 컨테이너에 배열 초기화 허용

내 생각에는 {1, 2 } 의 형식을 바로 타입(ex: int p[])으로 인식할수 있게끔 된것이 아닌가 생각이 드는데 확인을 해봐야 할것같다

std::vector<double> v = { 2.3, 1.2, 6.7, 4.5  };


- for each 형식의 문법 지원

네이티브 타입만 지원하는지 컨테이너도 지원 하는지 확인 해봐야 할듯

int my_array[5] = {1, 2, 3, 4, 5};
for(int &x : my_array)     // 참조 주목
{
    x *= 2;
}


- Lambda, Closure 형식 문법 지원

boost::lambda 은 정말 놀랍다.
그런데 이런걸 언어차원에서 지원하다니..

// 기존 for 문
for(vector<Widget>::iterator i = w.begin(); i != w.end(); ++i) {
    cout << *i << " ";
}

// boost::lambda
for_each( w.begin(), w.end(), cout << _1 << " " );

// C++0x lambda
for_each( w.begin(), w.end(), []( const Widget& w ) { cout << w << " "; } );



참고 사이트 :
http://blogs.msdn.com/vcblog/archive/2007/06/04/update-on-the-c-0x-language-standard.aspx
http://www.jong10.com/246

'Dev > C++' 카테고리의 다른 글

asio C++ library  (0) 2008.08.22
C++ 0x - Herb Sutter의 블로그 글  (0) 2008.07.29
memory pooling - code  (0) 2008.05.01
Is Derived - code  (0) 2008.05.01
C++에서 프로퍼티 구현하기  (0) 2008.05.01

MemPooling #

메모리 풀링 클래스

Efficient C++(Dov Bulka , David Mayhew)에서 많은 도움은 얻음
나름대로 좋은 성능을 냄

/**
 * MemPool.h
 *
 * Memory Pooling Class
 *
 * Copyright (c) 2004 by cdecl (byung-kyu kim)
 *
 */

#ifndef __MEM_POOL_H__BY__CDECL
#define __MEM_POOL_H__BY__CDECL


namespace GLASS {

// MemPool Class 
class MemPool
{
public:
    typedef unsigned int size_type;
    enum { DEFAULT_CHUNK_SIZE = 32 };

    struct MemNode { MemNode *next_; };

public:
    MemPool(size_type type_size, size_type chunk_size = DEFAULT_CHUNK_SIZE) :
        pHead_(0), pFree_(0), nUsed_(0),
        TYPESIZE(type_size > sizeof(MemNode*) ? type_size : sizeof(MemNode*)),
        CHUNK_SIZE(chunk_size)
    {
        ExpanseChunk();
    };
    ~MemPool() { Release(); }

public:
    void* malloc()
    {
        if (IsFull()) {
            if (pFree_) return (NodeNext(pFree_));

            ExpanseChunk();
        }

        int nOffSet = sizeof(MemNode*) + (TYPESIZE * nUsed_++);
        return (reinterpret_cast<char*>(pHead_) + nOffSet);
    }

    void free(void *p)
    {
        MemNode *pmn = reinterpret_cast<MemNode*>(p);
        pmn->next_ = pFree_;
        pFree_ = pmn;
    }

    void ExpanseChunk()
    {
        size_type nAllocSize = TYPESIZE * CHUNK_SIZE + sizeof(MemNode*);

        MemNode *pmn =
            reinterpret_cast<MemNode *>(::operator new(nAllocSize));

        nUsed_ = 0;;

        pmn->next_ = pHead_;
        pHead_ = pmn;
    }

    bool IsFull() const
    {
        return nUsed_ >= CHUNK_SIZE;
    }

    void Release()
    {
        while (pHead_ != 0) {
            ::operator delete(NodeNext(pHead_));
        }
    }

private:
    inline MemNode* NodeNext(MemNode *&pmn)
    {
        MemNode *p = pmn;
        pmn = pmn->next_;
        return p;
    }

private:
    // No Copy
    MemPool(const MemPool&);
    MemPool& operator=(const MemPool&);

private:
    MemNode *pHead_;
    MemNode *pFree_;

    size_type nUsed_;

private:
    const size_type TYPESIZE;
    const size_type CHUNK_SIZE;

};


} // namespace GLASS

#endif

'Dev > C++' 카테고리의 다른 글

C++ 0x - Herb Sutter의 블로그 글  (0) 2008.07.29
C++ 0x  (0) 2008.05.09
Is Derived - code  (0) 2008.05.01
C++에서 프로퍼티 구현하기  (0) 2008.05.01
boost::pool 예제  (0) 2008.05.01

Is Derived #


처음에 이 소스에서 template의 가능성을 보고 뒷통수를 맞은 기분 이었습니다.
기본적인 내용은 Base에서 Derived가 상속 되었느냐를 확인 하는 코드 입니다.
이 예제 뿐만 아니라 Modern C++ Design(Andrei Alexandrescu)에는 무궁무진한 template의 향연이 펼쳐집니다.


아래의 예제는 More Exceptional C++(Herb Sutter)에 나오는 내용입니다.
원본은 Andrei Alexandrescu에 의해 작성된 글이라고 More Exceptional C++에서 명시 하고 있습니다.
제가 컴파일러에서 테스트하고 수정한 소스입니다.
//////////////////////////////////////////////////////// 
#include <iostream>
using namespace std;


template <class Derived, class Base>
class IsDerived
{
private:
    class YES { char c[2]; };
    class NO {};

    static YES Test(Base *p);
    static NO Test(...);

public:
    // VC++, g++ 문제 없음 
    static bool Is()
    {
        return (sizeof(Test(static_cast<Derived *>(0))) == sizeof(YES));
    }

    // VC++ 문제없음 
    // g++ 3.2 컴파일 안됨 
    // g++ 3.4.1 에서는 문제 없음
    // enum { Is = (sizeof(Test(static_cast<Derived *>(0))) == sizeof(YES)) }; 

};


class B {};

class C : public B
{};


int main()
{
    cout << IsDerived<C, B>::Is() << endl;
}

'Dev > C++' 카테고리의 다른 글

C++ 0x  (0) 2008.05.09
memory pooling - code  (0) 2008.05.01
C++에서 프로퍼티 구현하기  (0) 2008.05.01
boost::pool 예제  (0) 2008.05.01
STLport 초간단 설치  (1) 2008.05.01

+ Recent posts