2010년 2월 25일 목요일

비주얼 스튜디오 2550 단축키 모음

비주얼 스튜디오2005 단축키 모음

Ctrl-K, Ctrl-H : 바로가기 설정. ( 작업목록 창에서 확인가능 )
Ctrl-K,K : 북마크 설정 / 해제
Ctrl-K,L : 북마크 모두 해제
Ctrl-K,N : 북마크 다음으로 이동
Ctrl-K,P : 북마크 이전으로 이동
Ctrl-K,C : 선택한 블럭을 전부 코멘트
Ctrl-K,U : 선택한 블럭을 전부 언코멘트(코멘트 해제)
Ctrl-F3 : 현재 단어 찾기
  -> F3 : 다음 찾기

Ctrl-F7 : 현 파일만 컴파일
            : 현 프로젝트만 빌드
Ctrl-Shift-B : 전체 프로젝트 빌드
Ctrl-F5 : 프로그램 시작

Ctrl-i : 일치하는 글자 연속적으로 찾기
Ctrl+i 를 누르면 하단에 자세히보면, "증분검색" 이라는 텍스트가 나온다.
그러면 그때 찾기 원하는 단어를 입력할때마다 일치하는 위치로 바로바로
이동한다. (좋은기능)
타이핑은 "증분검색" 이라는 텍스트옆에 커서는 없지만 입력이된다.
입력하는 문자를 수정하려면, backspace로, 그만 찾으려면 엔터.

줄넘버 보여주기 : 도구 > 옵션 > 텍스트편집기 > 모든언어 > 자동줄번호 선택하면 됨.

Ctrl+ - (대시문자), Ctrl+Shift+ -  :
현재 커서를 기억하는 Ctrl+F3(VS6에서), Ctrl+K,K(VS7에서) 와는 달리
사용자가 별도로 입력을 해주는건 없고, 단지 이전에 커서가 있었던곳으로
위 키를 누를 때마다 이동된다. (shift를 이용하면 역순)

Ctrl-F12 : 커서위치 내용의 선언으로 이동( 즉, 대략 헤더파일 프로토타입으로 이동)

F12 : 커서위치 내용의 정의로 이동( 즉, 대략 CPP파일 구현부로 이동)

Shift+Alt+F12 : 빠른기호찾기 ( 이거 찾기보다 좋더군요. 함수나 define등 아무거나에서 사용)

Alt+F12: 기호찾기. (s+a+f12 비교해볼것)

Ctrl-M, Ctrl-L : 소스파일의 함수헤더만 보이기 (구현부는 감추고) (토글 키)
Ctrl-M, Ctrl-M : 현재 커서가 위치한 함수를 접는다/편다. (토글 키)

#include "파일명" 에서 "파일명" 파일로 바로 직접이동
하고 싶을경우 -> Ctrl-Shift-G


<편집>---------------------------------------------------------------------------
Ctrl-F : 찾기 대화상자
Ctrl-H : 바꾸기 대화상자
Ctrl-Shift-F : 파일들에서 찾기 대화상자
Ctrl-Shift-H : 파일들에서 바꾸기 대화상자
Ctrl-G : 해당 줄로 가기 (별로 필요없음)
Ctrl-K,Ctrl-F : 선택된 영역 자동 인덴트 (VS6의 Alt-F8기능)
Ctrl-] :괄호({,}) 쌍 찾기 : 괄호 앞이나 뒤에서 눌러서 닫거나,
여는 괄호이동
Ctrl-Shift-Spacebar : 함수이름편집중 툴팁으로나오는 함수와매개변수설명이 안나올경우, 강제로 나오게

alt-LButton ->Drag : 원하는 영역의 블럭을 세로로 잡기

Ctrl+Shift+R (키보드 레코딩) :
  가끔 연속된 연속기만으로는 부족한경우가 있다.
  이럴때, 몇번의 키동작으로 레코딩하여, 이것을 반복하고 싶은경우가있다.
  이때 Ctrl+Shift+R 을 누르고, 원하는 동작들을 수행후, 다시 Ctrl+Shift+R을
  눌러 종료한다.  이 중간동작을 원하는 위치에서 반복하고 싶다면
  Ctrl+Shift+P 를 누른다.
 
Ctrl+Shift+V (히스토리 붙이기) :
  Ctrl + V와는 달리 클립보드에 있는 복사된내용을 돌아가면서 붙여준다.
  따로 복사를 해주거나 할 필요는 없다. 그냥 Ctrl+C로 계속 원하는것을
  복사하면 된다.

Ctrl-Z : 이전으로 되돌리기

Ctrl-Shift-Z : 되돌렸다, 다시 복구하기

 

 

<디버그/빌드>-------------------------------------------------------------------------
F5 : 디버그 시작
F9 :디버그 브렉포인트 설정
Ctrl-F9 : 현위치 설정된 브렉포인트 해제
Ctrl-Shift-F9 : 모든 브렉포인트 해
Shift-F5 : 디버그 빠져나오기
Ctrl-F10 : 커서가 있는곳까지 실행
Shift-F11 : 현 함수를 빠져나감.

Shift+Ctrl+B :  전체 빌드(프로젝트가 여러개있을경우 모두 빌드)
Alt+B, C : 해당 프로젝트만 정리.
Alt+B, U : 해당 프로젝트만 빌드.


 

<창관련>-------------------------------------------------------------------------

Shift+Alt+Enter : 전체 창 (토글 됨)
F4 : 속성창 보여준다.
Ctrl+Alt+X : 리소스에디터 툴박스창
Ctrl+Alt+K : 작업목록 창.


 

비주얼 스튜디오를 쓰다가 단축키를 잊어먹거나 까먹어서 잘 못쓰는 경우가 많아 정리를 해보았다.

단축키 설명
Ctrl + Tab Edit하고 있는 Child Window 간의 이동
Ctrl + F4 현재 Edit하고 있는 Child Window를 닫기
Ctrl + I 문자열 입력 점진적으로 문자열 찾기 (Incremental Search)
Ctrl + F3 현재 커서에 있는 문자열 찾기 fowared (블록 지정 안 해도 됨)
Shift + F3 현재 커서에 있는 문자열 찾기 backward
F3 찾은 문자열에 대한 다음 문자열로 이동 (Next Search)
Ctrl + H 문자열 찾아 바꾸기 (Replace)
Ctrl + Left/Right Arrow 단어 단위로 이동
Ctrl + Delete 또는 Backspace 단어 단위로 삭제
Ctrl + F2 현재 라인에 북마크 지정/해제
F2 지정된 다음 북마크로 이동
Ctrl + Shift + F2 지정된 모든 북마크를 해제
F9 현재 라인에 Breakpoint를 지정/해제
Ctrl + Shift + F9 현재 Edit하고 있는 소스파일에 지정된 모든 Breakpoint 해제
Ctrl + ] 또는 E '{'괄호의 짝을 찾아줌 ('{'에 커서를 놓고 눌러야 함}
Ctrl + J, K #ifdef 와 #endif의 짝을 찾아줌
Ctrl + L 한 라인을 클립보드로 잘라내기 (Cut)
Ctrl + Shift + L 한 라인을 삭제
Alt + Mouse 블록 설정 세로로 블록 설정하기 (마우스로)
Ctrl + Shift + F8 세로로 블록 설정하기 (키보드로), 취소할 때는 Esc키를 눌러야 함
블록 설정 -> Tab 선택된 블록의 문자열을 일괄적으로 들여쓰기(Tab) 적용
블록 설정 -> Shift + Tab 선택된 블록의 문자열을 일괄적으로 내어쓰기 적용
Alt + F8 -> Tab 또는 Shift + Tab 들여쓰기 자동 조정 (Tab:들여쓰기, Shift + Tab : 내어쓰기)
Ctrl + T 현재 커서에 있는 변수/함수에 대한 Type이 Tooltip 힌트 창에 나타남
Ctrl + Alt + T 멤버 변수/함수 목록에 대한 팝업 창이 나타남
Ctrl + Shift + T 공백/콤마/파이프/괄호 등을 기준으로 좌우 문자열을 Swap시킴
Ctrl + Shift + 8 문단기호 표시/감추기 : Tab은 ^, Space는 .으로 표시
Ctrl + D 툴바의 찾기 Editbox로 이동
Ctrl + Up/Down Arrow 커서는 고정시키고 화면만 스크롤 시키기


디버깅에 관련된 단축키 하나 더.
변수이름을 적어 놓고 브래이크 포인터의 위치 여부와 관계 없이 변수의 내용을 추적하는 기능이 Watch Window에 들어 있다. 디버그 모드에서 추가하고픈 변수나 등등 앞에 커서를 위치 시킨후 Shift + F9를 누르면 그냥 바로 추가된다.


Tab 들여쓰기,자동완성
Shift+Tab 내어쓰기
블록 설정 >> Tab 선택된 블록의 문자열을 일괄적으로 들여쓰기(Tab) 적용
블록 설정 >> Shift+Tab 선택된 블록의 문자열을 일괄적으로 내어쓰기 적용

 


F2 설정된 북마크로 이동
F2 설정된 다음 북마크로 이동
F3 다음 단어 찾기
F4 다음 에러메세지로 이동
F5 Debugging 모드로 작동
F9 현재 라인에 BreakPoint를 설정/해제
F10 Debugging 모드로 작동하되 엔트리 포인트부터 시작
F12 마우스 오른쪽 버튼 눌렀을때 go to definition 단축기

 

 

Ctrl+Up/Down Arrow 커서는 고정시키고 화면만 스크롤 시키기
ctrl+*(맨오른쪽 부분) 위에서 F12 눌렀을때 이전화면으로 돌아가기
Ctrl+Left/Right Arrow 단어 단위로 이동
Ctrl+Delete 또는 Backspace 단어 단위로 삭제
Ctrl+Tab Edit하고 있는 Child Window 간의 이동
Ctrl+Space 인텔리센스 출력(멤버목록 팝업창)

Ctrl+F2 북마크 설정
Ctrl+F2 현재 라인에 북마크 지정/해제
Ctrl+F3 현재 커서에 있는 단어로 찾기
Ctrl+F4 현재 Edit하고 있는 Child Window를 닫기
Ctrl+F5 빌드 후 프로그램 실행
Ctrl+F10 Debugging 모드로 작동하되 커서의 위치까지

Ctrl+] 괄호 짝 찾기
Ctrl+] 또는 E {괄호의 짝을 찾아줌 ({에 커서를 놓고 눌러야 함}
Ctrl+A 전체 선택
Ctrl+B 브레이크 포인트 관리 메뉴
Ctrl+D 툴바의 찾기 Editbox로 이동
Ctrl+E 현재 괄호랑 맞는 괄호를 찾아준다.
Ctrl+F 현재 커서에 있는 단어로 찾기
Ctrl+G 라인 바로 가기(GoTo)
Ctrl+H 문자열 찾아 바꾸기 (Replace)
Ctrl+I >> 문자열 입력 점진적으로 문자열 찾기 (Incremental Search)
Ctrl+J, K #ifdef 와 #endif의 짝을 찾아줌
Ctrl+L 한 라인을 클낳링藥?잘라내기 (Cut)
Ctrl+T 현재 커서에 있는 단어의 툴팁정보 보기
Ctrl+U 모두 소문자로
Ctrl+W 클래스 위자드 (MFC 코딩시에만 사용)

Ctrl+Shite+Space 현재 가르키고 있는 함수의 매개변수 보기

Ctrl+Shift+F2 지정된 모든 북마크를 해제
Ctrl+Shift+F3 이전 단어 찾기
Ctrl+Shift+F8 열 블럭(키보드로), 취소할 때는 Esc키를 눌러야 함
Ctrl+Shift+F9 현재 Edit하고 있는 소스파일에 지정된 모든 Breakpoint 해제

Ctrl+Shift+8 문단기호 표시/감추기 : Tab은 ^, Space는 .으로 표시

Ctrl+Shift+L 한 라인을 삭제
Ctrl+Shift+P 매크로 실행
Ctrl+Shift+R 매크로 기록
Ctrl+Shift+T 공백/콤마/파이프/괄호 등을 기준으로 좌우 문자열을 Swap시킴
Ctrl+Shift+U 모두 대문자로

Ctrl+Alt+T 멤버 변수/함수 목록에 대한 팝업 창이 나타남

 

 

Alt+MouseMove 컬럼 Selection

Alt+B -> E Clean
Alt+B -> R Rebuild All
Alt+E+I 프로젝트 내의 모든 파일에서 찾기
Alt+G 그 함수가 선언된 파일이나 위치로 고!
Alt+O 헤더와 소스파일을 번갈아 보여줌

Alt+0 WorkSpace 윈도우
Alt+2 output 윈도우

Alt+F7 Project Setting
Alt+F8 들여쓰기 자동 조정
Alt+F9 브레이크포인트 관리

2010년 2월 23일 화요일

[지윤정의 직장심리탐구]밀어주고 당겨주는 팔로워십

 

ZD Net Korea 칼럼입니다.

 

입사 초년생들이라면 한번쯤 읽어 볼만한 칼럼 인거 같습니다.

 

칼럼보러가기

 

펼쳐두기..

2010년 2월 22일 월요일

ASP Class, Dictionary, 클래스, 딕셔너리

php에만 심취하다가 새로온 회사에서 asp 위주라서 asp를 정말 몇년만에 접하게 되었다.
php에서 클래스 쓰는게 몸에 익어서 asp도 클래스를 써볼까 해서 asp 잘하시는분에게 asp에서 클래스는 어떻게 하면 되는지 물었다. 그런데. asp에는 클래스가 없다는거다!!!

헉.. 이런 췐장.. 그럼 함수로 인클루드 해서 다해야하는거야? 라고 낙담을 하다가.. 혹시나 해서 구글에서 열라 찾아봤다. 그러다 보니.. 클래스가 있었다. asp에도 클래스가 있는거다.

우리나라 asp 책 어디에도 나와있지 않은 클래스가 있는거다.
그래서.. 혹시나 asp는 클래스가 없다고 생각하시는분들을 위해서 강좌 아닌 소개수준의 글을 적어본다. 물론 기억력 나쁜 나에게도 대체 기억장치로 글을 남긴다.

그리고 본 글은 다른 언어에서 클래스를 접해 본 분들을 위해 간단한 소개 수준이라 클래스가 무엇인지? 라는 원론적인 이야기는 하지 않는다.

ASP에는 아쉽게도 상속이 되질 않는다. ASP.NET에 가면 지원된다고 들은것같기도 하지만 오리지날  ASP에는 지원되지 않는다. 이점도 유의 하시고..

ASP 클래스의 시작

CLASS TESTCLASS
  .....
END CLASS


일단 시작은 저렇게 시작하고 마친다. 보통의 SUB 나 FUNCTION이랑 비슷하다.

그리고 클래스의 시작과 마침에 자동으로 실행되는 함수를 넣어야 하는데 아래와 같다

Private Sub Class_Initialize()
... 클래스 생성될때 자동으로 실행
END SUB
Private Sub Class_Terminate()
... 클래스 닫힐때 자동으로 실행
END SUB


위는 보통 디비는 항상 열고 닫기 때문에  두 함수에 DB를 열고 닫는것을 넣어두면 편하다.
물론,, 디비접속과 아무관련이 없는 클래스의 경우 넣을 필요는 없다.

여튼 여기까지를 한번에 묶으면 ..


CLASS TESTCLASS

    private thisDbCon

    Private Sub Class_Initialize()
       '디비접속
        Set thisDbCon=Server.CreateObject("ADODB.Connection")
        StrDBConnect = "Provider=ORAOLEDB.ORACLE;Password=***;User ID=****;Data Source=****;Persist Security Info=True;"
        thisDbCon.Open StrDBConnect

    END SUB
    Private Sub Class_Terminate()
       '디비 끊기
        thisDbCon.Close
        thisDbCon=Noting
    END SUB
END CLASS


이게 기본 세트라고 할수 있다. 이 이후에는 클래스에 함수들을 하나씩 추가시키면 된다. 그러면 알흠다운 클래스가 만들어지게 되겠다.

그러면 만들어 놓은 클래스를 다른 페이지에서 불러서 사용하는 방법을 보겠다.

먼저 저 클래스를 CLASS.TEST.ASP 라는 이름으로 저장한다.
이름에 CALSS가 들어가는건 특별한 이유가 있는게 아니고 그냥 다른 파일들과 구분하기 위한것이니 이름은 원하는데로 해도 상관없다

<!--#include virtual="CLASS.TEST.ASP"-->


먼저 페이지 상단에 위와같이 클래스를 인클루드 시킨다.

SET CLASSTEST=NEW CLASSTEST


그런 다음 위와 같이 클래스를 생성한다.

클래스의 좋은 점은 함수와 달리 클래스를 생성하면 같은 함수들이 독립적으로 작동된다는것이다.

SET CLASS1=NEW CLASSTEST
SET CLASS2=NEW CLASSTEST
SET CLASS3=NEW CLASSTEST


이렇게 생성해서 사용해도 클래스안의 같은 이름의 변수나 함수들이 독립적으로 행동할수 있다는것이다. 그리고 그냥 인클루드로 함수들을 나열해서 인클루드 할때보다 정리가 쉽고 다른 사이트에 적용하기도 좋다

클래스가 왜 좋은지 사용하기 좋은지에 대한건 구글이나 네이버에 찾아봐주시고~

일단 생성된 클래스의 함수를 실행해 보겠다.

CLASS TEST
    Private Sub Class_Initialize()
    END SUB
   Private Sub Class_Terminate()
    END SUB
  'A+B 함수
    PUBLIC FUNCTION GETSUM(A,B)
       GETSUM=A+B
    END FUNCTION
END CLASS


SET T=NEWTEST
RESPONSE.WRITE T.GETSUM(10,20)

위의 간단한 합계 함수이다. 화면에는 30이 뿌려질테고..

저걸 좀더 바꿔보면..

CLASS TEST
   Private Sub Class_Initialize()
   END SUB
  Private Sub Class_Terminate()
   END SUB
 
    PUBLIC FUNCTION GETSUM(NUMARR)
       DIM I,RESULT
      FOR I=0 TO UBOUND(NUMARR)
        RESULT=RESULT+NUMARR(I)
     NEXT
       GETSUM=RESULT
    END FUNCTION
END CLASS

SET T=NEWTEST

DIM NUMBERS(4)
NUMBERS(0)=10
NUMBERS(1)=20
NUMBERS(2)=100
NUMBERS(3)=200
RESPONSE.WRITE T.GETSUM(NUMBERS)


머 이렇게 배열변수를 바로 넘겨서 사용할수도 있다.


PUBLIC & PRIVATE

PUBLIC 과 PRIVATE 는 다 알다시피 광역이냐 지역이냐 이다.
클래스 안에 쓰이는 변수들이나 함수앞에 PUBLIC 을 붙이면 클래스 밖에서도 사용가능하다. 위의 함수 GETSUM 도 앞에 PUBLIC 이 붙어 있기 때문에 클래스 밖에서 실행이 가능한것이다.

반대로 PRIVATE가 붙으면 클래스 내부에서만 실행된다. 외부에서 불러낼려치면 호출 오류가 뜰것이다.

이건 변수들도 마찬가지다.



추가 팁(?) 딕셔너리 주고 받기
PHP 에서는 배열 자체가 딕셔너리같은거라 주고 받기 편했는데.. ASP에서 이 방법을 찾는데 꽤나 고생했다. 혹시나 같은 고생하는 분이 있을까 해서 적어 본다

이걸 클래스와 연결해서 보면..

CLASS DICTEST

    PUBLIC FUNCTION GETDIC()

        Set D=CreateObject("Scripting.Dictionary")
        D.add "BANANA", "100"
        D.ADD "DDALGI","200"
        D.ADD "SO","300"

        SET GETDIC = D

    END FUNCTION
END CLASS

'사용하기

Set DICTEST=NEW DICTEST
SET DATA=DICTEST.GETDIC

RESPONSE.WRITE DATA("BANANA")



보낼때나 받을때나 SET 을 붙여주는게 포.인.트


대충 이정도로 강좌 아닌 소개를 마칠까 한다. 먼가 중요한 무언가를 빼먹은것같은 기분은 머지??


대충 찾은 클래스 소개 페이지들
http://blog.naver.com/yanione?Redirect=Log&logNo=70016736125
http://www.daniweb.com/tutorials/tutorial19997.html (아쉽게도 영어)

 

출처 : http://www.moonseller.net/21

[ETC] 정규식

http://en.wikipedia.org/wiki/Regular_expression

http://www.regular-expressions.info/

 

http://blog.outsider.ne.kr/141

http://blog.outsider.ne.kr/360

 

 

Examples of Regular Expressions

JScript VBScript Matches

/^\s[ \t]*$/

"^\s*$"

Match a blank line.

/\d{2}-\d{5}/

"\d{2}-\d{5}"

Validate an ID number consisting of 2 digits, a hyphen, and another 5 digits.

The following table contains the complete list of metacharacters and their behavior in the context of regular expressions:

Character Description

\

Marks the next character as a special character, a literal, a backreference, or an octal escape. For example, 'n' matches the character "n". '\n' matches a newline character. The sequence '\\' matches "\" and "\(" matches "(".

^

Matches the position at the beginning of the input string. If the RegExp object's Multiline property is set, ^ also matches the position following '\n' or '\r'.

$

Matches the position at the end of the input string. If the RegExp object's Multiline property is set, $ also matches the position preceding '\n' or '\r'.

*

Matches the preceding character or subexpression zero or more times. For example, zo* matches "z" and "zoo". * is equivalent to {0,}.

+

Matches the preceding character or subexpression one or more times. For example, 'zo+' matches "zo" and "zoo", but not "z". + is equivalent to {1,}.

?

Matches the preceding character or subexpression zero or one time. For example, "do(es)?" matches the "do" in "do" or "does". ? is equivalent to {0,1}

{n}

n is a nonnegative integer. Matches exactly n times. For example, 'o{2}' does not match the 'o' in "Bob," but matches the two o's in "food".

{n,}

n is a nonnegative integer. Matches at least n times. For example, 'o{2,}' does not match the "o" in "Bob" and matches all the o's in "foooood". 'o{1,}' is equivalent to 'o+'. 'o{0,}' is equivalent to 'o*'.

{n,m}

m and n are nonnegative integers, where n <= m. Matches at least n and at most m times. For example, "o{1,3}" matches the first three o's in "fooooood". 'o{0,1}' is equivalent to 'o?'. Note that you cannot put a space between the comma and the numbers.

?

When this character immediately follows any of the other quantifiers (*, +, ?, {n}, {n,}, {n,m}), the matching pattern is non-greedy. A non-greedy pattern matches as little of the searched string as possible, whereas the default greedy pattern matches as much of the searched string as possible. For example, in the string "oooo", 'o+?' matches a single "o", while 'o+' matches all 'o's.

.

Matches any single character except "\n". To match any character including the '\n', use a pattern such as '[\s\S].

(pattern)

Matches pattern and captures the match. The captured match can be retrieved from the resulting Matches collection, using the SubMatches collection in VBScript or the $0$9 properties in JScript. To match parentheses characters ( ), use '\(' or '\)'.

(?:pattern)

Matches pattern but does not capture the match, that is, it is a non-capturing match that is not stored for possible later use. This is useful for combining parts of a pattern with the "or" character (|). For example, 'industr(?:y|ies) is a more economical expression than 'industry|industries'.

(?=pattern)

Positive lookahead matches the search string at any point where a string matching pattern begins. This is a non-capturing match, that is, the match is not captured for possible later use. For example 'Windows (?=95|98|NT|2000)' matches "Windows" in "Windows 2000" but not "Windows" in "Windows 3.1". Lookaheads do not consume characters, that is, after a match occurs, the search for the next match begins immediately following the last match, not after the characters that comprised the lookahead.

(?!pattern)

Negative lookahead matches the search string at any point where a string not matching pattern begins. This is a non-capturing match, that is, the match is not captured for possible later use. For example 'Windows (?!95|98|NT|2000)' matches "Windows" in "Windows 3.1" but does not match "Windows" in "Windows 2000". Lookaheads do not consume characters, that is, after a match occurs, the search for the next match begins immediately following the last match, not after the characters that comprised the lookahead.

x|y

Matches either x or y. For example, 'z|food' matches "z" or "food". '(z|f)ood' matches "zood" or "food".

[xyz]

A character set. Matches any one of the enclosed characters. For example, '[abc]' matches the 'a' in "plain".

[^xyz]

A negative character set. Matches any character not enclosed. For example, '[^abc]' matches the 'p' in "plain".

[a-z]

A range of characters. Matches any character in the specified range. For example, '[a-z]' matches any lowercase alphabetic character in the range 'a' through 'z'.

[^a-z]

A negative range characters. Matches any character not in the specified range. For example, '[^a-z]' matches any character not in the range 'a' through 'z'.

\b

Matches a word boundary, that is, the position between a word and a space. For example, 'er\b' matches the 'er' in "never" but not the 'er' in "verb".

\B

Matches a nonword boundary. 'er\B' matches the 'er' in "verb" but not the 'er' in "never".

\cx

Matches the control character indicated by x. For example, \cM matches a Control-M or carriage return character. The value of x must be in the range of A-Z or a-z. If not, c is assumed to be a literal 'c' character.

\d

Matches a digit character. Equivalent to [0-9].

\D

Matches a nondigit character. Equivalent to [^0-9].

\f

Matches a form-feed character. Equivalent to \x0c and \cL.

\n

Matches a newline character. Equivalent to \x0a and \cJ.

\r

Matches a carriage return character. Equivalent to \x0d and \cM.

\s

Matches any white space character including space, tab, form-feed, and so on. Equivalent to [ \f\n\r\t\v].

\S

Matches any non-white space character. Equivalent to [^ \f\n\r\t\v].

\t

Matches a tab character. Equivalent to \x09 and \cI.

\v

Matches a vertical tab character. Equivalent to \x0b and \cK.

\w

Matches any word character including underscore. Equivalent to '[A-Za-z0-9_]'.

\W

Matches any nonword character. Equivalent to '[^A-Za-z0-9_]'.

\xn

Matches n, where n is a hexadecimal escape value. Hexadecimal escape values must be exactly two digits long. For example, '\x41' matches "A". '\x041' is equivalent to '\x04' & "1". Allows ASCII codes to be used in regular expressions.

\num

Matches num, where num is a positive integer. A reference back to captured matches. For example, '(.)\1' matches two consecutive identical characters.

\n

Identifies either an octal escape value or a backreference. If \n is preceded by at least n captured subexpressions, n is a backreference. Otherwise, n is an octal escape value if n is an octal digit (0-7).

\nm

Identifies either an octal escape value or a backreference. If \nm is preceded by at least nm captured subexpressions, nm is a backreference. If \nm is preceded by at least n captures, n is a backreference followed by literal m. If neither of the preceding conditions exist, \nm matches octal escape value nm when n and m are octal digits (0-7).

\nml

Matches octal escape value nml when n is an octal digit (0-3) and m and l are octal digits (0-7).

\un

Matches n, where n is a Unicode character expressed as four hexadecimal digits. For example, \u00A9 matches the copyright symbol (©).

 

오라클 서적

초/중급 : Beginning Oracle Programming 

 

한국마이크로소프트 : IT Trend 2010

한국마이크로소프트 : IT Trend 2010

 

1. 클라우드 컴퓨팅

2. 그린 IT

3. 마켓플레이스

4. 모바일

5. 3스크린 전략과 새로운 사용자경험(UX) 기술

6. 가상화

7. 소셜리틱 애플리케이션

8. 통합보안환경

9. IT거버넌스

10. 소프트웨어 품질

2010년 2월 18일 목요일

IBM : jQuery

* jQuery로 Ajax 개발을 단순화 하기 - 2007년 9월 4일 (화)  
(http://www.ibm.com/developerworks/kr/library/x-ajaxjquery.html)

펼쳐두기..



* Ajax로 사이트 전면 개편, Part 1: Ajax와 jQuery로 기존 사이트 개선하기 - 2008년 4월 15일 (화)
(http://www.ibm.com/developerworks/kr/library/wa-aj-overhaul1/index.html)

 

펼쳐두기..

       


* Ajax로 사이트 전면 개편, Part 2: jQuery, Ajax, 툴팁, 라이트박스로 기존 사이트 개선하기 - 2008년 6월 17일 (화)
(http://www.ibm.com/developerworks/kr/library/wa-aj-overhaul2/index.html)

펼쳐두기..

             

* Ajax로 사이트 전면 개편, Part 3: jQuery, Ajax 탭, 회전식 슬라이드쇼로 기존 사이트 개선하기 - 2008년 9월 23일
(화)
(http://www.ibm.com/developerworks/kr/library/wa-aj-overhaul3/index.html)

 

펼쳐두기..

   


* Ajax로 사이트 전면 개편, Part 4: 기존 사이트를 jQuery와 Ajax forms를 사용하여 개선하기 - 2008년 9월 30일 (화)
(http://www.ibm.com/developerworks/kr/library/wa-aj-overhaul4/index.html)

펼쳐두기..




* jQuery로 작업하기, Part 1: 브라우저로 데스크톱 응용 옮기기 - 2008년 11월 18일 (화)   
(http://www.ibm.com/developerworks/kr/library/wa-jquery1/index.html)

펼쳐두기..




* jQuery로 작업하기, Part 2: 내일 나올 웹 응용을 오늘 구현해보자 - 2008년 11월 25일 (화)
(http://www.ibm.com/developerworks/kr/library/wa-jquery2/index.html)

펼쳐두기..

 

출처 : taeyo.net 팁게시판 hskim618님

2010년 2월 17일 수요일

oracle 10g 암호화/복호화

-- 암호화 함수
CREATE OR REPLACE FUNCTION f_Encrypt (p_Input_str  in varchar2) RETURN VARCHAR2
AS
 v_Input_len number := ROUND(LENGTH(p_Input_str)/8+0.5)*8;
 v_Encrypted_str varchar2(2000) := null;
 v_Key varchar2(16) := 'abcdefgh12345678';
BEGIN
   DBMS_OBFUSCATION_TOOLKIT.DESENcrypt(input_string => RPAD(p_Input_str,
                                       v_Input_len),
                                       key_string => v_Key,
                                       encrypted_string =>v_Encrypted_str);

   RETURN v_Encrypted_str;
END;
/

-- 복호화 함수
CREATE OR REPLACE FUNCTION f_Decrypt (p_Encrypted_str in varchar2) RETURN VARCHAR2
AS
 v_Key varchar2(16) := 'abcdefgh12345678';
 v_Decrypted_str varchar2(2000);
BEGIN
   DBMS_OBFUSCATION_TOOLKIT.DESDecrypt(input_string => p_Encrypted_str,
                                     key_string => v_Key,
                                     decrypted_string => v_Decrypted_str);

   RETURN trim(v_Decrypted_str);
END;
/

 


10g

암호화 함수

CREATE OR REPLACE FUNCTION pv_encrypt(v_in_string VARCHAR2)

RETURN RAW IS

    input_raw RAW(1024);

    key_raw RAW(16) := UTL_RAW.CAST_TO_RAW('abcdefghijklmnop');

    v_out_raw RAW(1024);

    AES_CBC_PKCS5 CONSTANT PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES128

                                               + DBMS_CRYPTO.CHAIN_CBC

                                                                         + DBMS_CRYPTO.PAD_PKCS5;

BEGIN

    input_raw := UTL_I18N.STRING_TO_RAW(v_in_string, 'AL32UTF8');

    v_out_raw := DBMS_CRYPTO.ENCRYPT(

        src => input_raw,

             typ => AES_CBC_PKCS5,

        key => key_raw);

 

    RETURN v_out_raw;

 

END pv_encrypt;

/

복호화 함수

CREATE OR REPLACE FUNCTION pv_decrypt(v_in_raw RAW)

RETURN VARCHAR2 IS

    key_raw RAW(16) := UTL_RAW.CAST_TO_RAW('abcdefghijklmnop');

    output_raw RAW(1024);

    v_out_string VARCHAR2(1024);

    AES_CBC_PKCS5 CONSTANT PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES128

                  + DBMS_CRYPTO.CHAIN_CBC

                             + DBMS_CRYPTO.PAD_PKCS5;

BEGIN

    output_raw := DBMS_CRYPTO.DECRYPT(

        src => v_in_raw,

        typ => AES_CBC_PKCS5,

        key => key_raw);

 

    v_out_string := UTL_I18N.RAW_TO_CHAR(output_raw, 'AL32UTF8');

    RETURN v_out_string;

 

END pv_decrypt;

2010년 2월 10일 수요일

ASP 엑셀 한글깨짐

헤드에 추가

<meta http-equiv="Content-Type" content="application/vnd.ms-excel;charset=euc-kr">

2010년 2월 5일 금요일

ASP DB 액세스 튜닝 사례 및 DBHelper 소개

Written by 안재우(Jaewoo Ahn), 닷넷엑스퍼트(.netXpert)

 

이번 글은 ASP에 대한 팁입니다. 근데, 갑자기 뜬금없이 ASP냐구요?

실은 얼마전 회사의 김태영 씨가 요청을 해서 예전 S사의 튜닝 프로젝트에서 만들었던 DBHelper라는 ASP용 데이터 액세스 헬퍼 클래스를 태요 사이트(http://www.taeyo.net)에 공개했습니다.

강좌 페이지는 http://www.taeyo.net/Lecture/20_Tips/DBHelper.asp 이며, 관련된 소스 및 문서는 http://www.taeyo.net/Lecture/20_Tips/source/DBHelper.zip에서 다운받을 수 있습니다.

 

위 문서에 있는대로 사실 DBHelper는 별다른 대단한 녀석은 아닙니다. 단지 ASP에서 권장되는 데이터 액세스 기법들을 활용해서 유틸리티 함수들을 묶은 스크립트 클래스에 불과합니다. 사실 클래스 자체보다는 그러한 바탕이 되는 기법들이 무엇이고 왜-어째서 이런 기법들을 사용해야 하는지가 더욱 중요한 것이겠죠.

 

이번 글에서는 실제 튜닝 프로젝트 사례를 바탕으로 튜닝 시나리오, ASP 데이터 액세스 기법 및 팁, 그리고 DBHelper에 대해 설명하도록 하겠습니다.

 

1. 프로젝트의 배경

S사는 Windows 2000, IIS 5.0인 웹 서버 10대, Windows 2000, SQL 2000 Enterprise로 클러스터링된 DB 서버 2대로 운영되는 중형 규모의 ASP 사이트였습니다. S사에서 제기해 온 문제는 서버의 성능이 너무 떨어진다는 것이었습니다. 조사 결과 웹 서버의 부하는 상당히 낮은 편인데 비해 DB 서버의 부하가 상당히 높은 편이었습니다. 사용자가 늘어나면서 이러한 성능 문제는 점점 더 심각해졌고, 그에 따른 Capacity 한계 때문에 S사는 W2K-IIS-ASP-SQL 기반의 플랫폼에 의구심을 가지고 있던 상황이었습니다.

 

논의 결과 2가지 사항에 크게 주목하게 되었습니다.

첫째는 DB 내부의 문제입니다. DB 구조 자체가 잘못 되었거나, 인덱스가 걸려 있지 않거나 혹은 잘못 걸려 있는 경우, 그리고 DB 구조 때문에 쿼리 자체가 상당히 복잡한 경우 등입니다. 즉 이 경우는 효율적인 DB 튜닝을 통해 성능을 개선할 수 있습니다. 테이블 구조 변경, 인덱싱, 자주 사용하는 쿼리를 SP로 변환하는 것 등이 해당 작업이 되겠습니다.

 

둘째는 웹 서버의 부하가 너무 적다는 것입니다. S사의 경우 부하가 매우 DB 서버에 편중되어 있으므로, 이를 웹 서버에 분담시킬 수 있는 방법을 고려하는 것이 바람직하다고 판단되었습니다. 이를 위해서는 애플리케이션의 코드를 분석하고, 데이터 액세스를 어떻게 하고 있는지를 파악하는 것이 필요합니다.

 

작업은 어디까지나 튜닝의 범위 내에서 수행하기로 했습니다. 즉 플랫폼을 교체한다거나 아키텍처를 완전히 갈아엎는다거나, 하드웨어를 추가로 구매하는 것은 고려하지 않기로 했습니다. 이에 따라 DB 튜닝과 애플리케이션 튜닝을 병행해서 작업을 하도록 결정하였습니다.

DB 튜닝은 제 영역이 아니므로 이 글에서는 다루지 않도록 하겠습니다. 이런 쪽은 DB 전문가 분들께 문의해보시는게 빠르겠죠? ^^

 

2. 튜닝의 기초 개념 : 부하의 분산

 

우리가 알아야 할 사항 중 하나는 기본적으로 애플리케이션의 로직 등에 문제가 없다고 가정할 때, 부하는 없어지지 않고 옮겨질 뿐입니다. 예를 들어 전체 부하가 100이라고 할 경우, 이 부하는 웹 서버와 DB 서버들에 각각 나누어져서 존재합니다.

 

따라서 분산 애플리케이션 튜닝에서 해야 할 사항 중 하나는 이러한 부하를 골고루 분산하는 것입니다. 여기에서 감안해야 할 사항은 확장성(Scalability)입니다. 통상적으로 웹 서버는 스케일 아웃(Scale-Out)을 통해 확장을 하기가 용이합니다. 즉 웹 서버의 대수를 늘리고 L4 등을 통해 로드밸런싱으로 묶기만 하면 분산이 가능합니다. 이에 비해 DB 서버의 경우 확장성은 상당히 제한적입니다. 통상적으로 스케일 아웃은 클러스터링을 통해서만 확장이 가능하며 클러스터링을 할 수 있는 서버의 수도 제한될 뿐더러 비용 역시 상당히 비싼 대가를 치러야 합니다. 그렇지 않으면 스케일 업(Scale-Up), 즉 서버의 사양을 업그레이드시키는 것으로만 해결이 가능합니다. 그러나 아쉽게도 Windows 2000 서버는 CPU 개수를 무한히 늘릴 수 없으며, 제한적입니다.

 

DB 서버와 웹 서버는 사양 및 성능에 있어서 분명한 차이가 존재합니다. 일반적으로 DB 서버가 훨씬 더 뛰어난 사양을 가집니다. S사의 DB 서버와 웹 서버의 경우는 CPU 갯수만 하더라도 8CPU와 2CPU라는 성능 차이를 가지고 있었습니다.

 

얘기를 풀어나가기 위해 일단 각 DB 서버의 최대 부하 한계가 50, 최대 웹 서버의 부하 한계가 20이라고 대략 가정해 보도록 합시다.

현재는 DB 서버 쪽이 70, 웹 서버 쪽이 30인 상태였습니다. 이 경우 DB 서버는 1대당 35, 웹 서버는 1대당 기껏 4의 부하만을 가지고 있는 셈입니다. DB 서버는 자기 한계를 70%(35/50)를 이미 사용하고 있으며, 웹 서버는 자기 한계의 20%(4/20)만을 기껏 사용하고 있는 셈입니다.

(35 * DB 서버 2대) + (3 * 웹 서버 10대) = 100

 

우리가 바라는 것은 최소한 DB 서버 쪽을 40, 웹 서버 쪽을 60으로 만드는 것이었습니다. 이 경우 DB 서버는 1대당 20, 웹 서버는 1대당 6의 부하만을 가지면 됩니다. 이 경우 DB 서버는 40%, 웹 서버는 30%로 되는 셈입니다.

(20 * DB 서버 2대) + (6 * 웹 서버 10대) = 100

 

DB 서버 쪽을 30, 웹 서버 쪽을 70으로 만들면 안되나요? 아, 물론 가능할 수도 있습니다. 이 경우 DB 서버는 1대당 15, 웹 서버는 1대당 7의 부하를 가지게 됩니다. 이 경우 DB 서버는 30%, 웹 서버는 35%로 되는 셈입니다.

(15 * DB 서버 2대) + (7 * 웹 서버 10대) = 100

 

대신 마지막으로 알아두어야 할 사항은 이러한 부하를 한쪽으로 몽땅 옮길 수는 없으며, 옮길 수 있는 한계가 존재한다는 것입니다. 최소한 DB 서버에서만 수행가능한 작업, 웹 서버에서만 수행 가능한 작업은 반드시 존재한다는 것이죠. 애플리케이션과 시스템의 성격에 따라 1:9, 2:8, 3:7, ..., 8:2, 9:1 등은 존재할 수 있지만 0:10이나 10:0은 존재할 수 없다는 것을 의미합니다.

 

쉽게 설명하려고 노력했는데 이해가시죠? ^^ 참고로 튜닝에는 부하 분산만이 존재하는 것은 아니라는 것을 알아 두세요.

 

3. 기존 애플리케이션 분석

우선 기존 애플리케이션을 분석하기로 했습니다. S사 사이트는 페이지 수가 상당히 많은 편이며, 구조도 비교적 복잡한 편이었습니다. 그에 따라 디렉터리 구조도 나름대로 체계적으로 나누기 위해 노력한 편이었으며, 공통된 내용들은 .inc로 철저하게 분리해내려고 노력한 흔적이 많이 보였습니다. 즉, 일반적인 ASP 사이트보다 나쁘지는 않은(?) 상황이었다는 것입니다.

 

S사는 DB 액세스를 하기 위해 크게 2개의 inc 파일을 사용하고 있었습니다. 즉 페이지의 앞 부분에 삽입된 inc에서는 ADO Connection 개체를 생성하고, 페이지 내에서는 이 Connection 개체를 가지고 DB 액세스를 수행한 후, 페이지의 뒷 부분에 inc 파일을 삽입하여 Connection을 닫고 Connection 개체를 Nothing 처리하는 전형적인 패턴을 사용하고 있었습니다.

이런 경우 inc 파일만 제대로 넣어준다면 커다란 문제는 생기지 않습니다. 결국 문제는 inc 파일들이 아니라 Connection을 가지고 실제 DB에 액세스하는 코드에 문제가 있는 셈입니다.

 

분석 결과.. 역시 코드가 문제였습니다.

가장 무엇보다 큰 문제는 DB 액세스를 위해 사용하는 코드가 전부 다 제각각이라는 점이었습니다. 사람들마다 사용하는 커서도 제각각이었으며, ADO 관련 상수를 쓰는 사람도 있고 아닌 사람도 있고, 심지어 어떤 사람은 자기가 직접 Connection을 만들어서 사용하는 사람도 있었습니다. 많은 수의 개발자가 작성하고, 시도 때도 없이 유지 보수를 위해 코드를 수정하는 경우에는 허다하게 일어나는 일입니다. 심지어 1번만 수행되면 되는 쿼리를 쓸데없이 while 루프 안에 집어 넣어서 한 페이지 내에서 동일한 쿼리가 수십번 실행되는 페이지도 존재했습니다.

두번째 문제는 대부분의 코드가 DB 서버에 부하를 많이 주는 방식이었습니다. 서버의 자원을 사용하는 Connected Recordset, 서버 사이드 커서 등이 사용되는 경우가 많았습니다.

또한 쿼리 자체도 SP도 아니며, 파라미터화된 쿼리도 아니며, 문자열 조합 쿼리가 거의 대부분이었습니다.

 

결과적으로 공통된 DB 액세스 코딩 패턴을 제공하고, DB 서버의 자원을 적게 쓰는 DB 액세스 기법들을 사용하고, 문자열 조합 쿼리를 파라미터화된 쿼리 또는 SP로 변환하는 것을 권고안으로 제시했습니다.

 

4. ASP 데이터 액세스 기법 살펴보기

여기서는 DBHelper에 쓰인 기법들을 자세히 살펴보도록 하겠습니다. DBHelper는 이러한 3가지를 사용하기 쉽도록 지원하기 위한 산출물인 셈이죠.

 

1) Connected Recordset vs. Disconnected Recordset

 

일반적으로 ADO에서 사용되는 레코드셋은 연결된 레코드셋(Connected Recordset)으로 레코드셋에서 작업을 하기 위해서는 Connection이 열려 있어야 하며, 레코드셋에서 MoveNext 또는 MovePrevious와 같은 작업을 하는 경우 DB와 계속적으로 상호작용을 하게 됩니다.
이 경우 오랜 시간 Connection 자원을 열어놓고 사용하게 되므로 자원적인 낭비와 궁극적으로는 DB 서버의 성능 저하를 초래하며, 커서를 사용하는 동안 DB와의 라운드 트립이 발생하게 됩니다.

 

ADO은 연결된 레코드셋 외에 별도로 비연결 레코드셋(Disconnected Recordset)을 지원합니다. 비연결 레코드셋이라 함은 말 그대로 DB와 연결이 없는 레코드셋을 말합니다. 예를 들어 비연결 레코드셋에서 MoveNext, MovePrevious와 같은 레코드 네비게이션(navigation) 메서드들이 호출되더라도 DB와 어떠한 상호작용도 하지 않습니다.

 

이것이 가능케하기 위해서 비연결 레코드셋은 클라이언트 커서 라이브러리를 사용합니다. 즉, 레코드셋 객체의 CusorLocation 프로퍼티의 값이 adUseClient이어야만 비연결 레코드셋을 만들 수 있습니다. 비연결 레코드셋을 만드는 방법은 다음과 같이 간단하게 레코드셋 객체의 ActiveConnection 속성 값을 Nothing으로 설정하면 됩니다.

 

Dim strConn, strSQL
Dim adoRS

 

strSQL = "SELECT * FROM Suppliers"
strConn = "Provider=SQLOLEDB;Data Source=(local);Initial Catalog=NorthWind;User ID=sa;"

 

Set adoRS = Server.CreateObject("ADODB.RecordSet")
Set adoRS.CursorLocation = adUseClient

adoRS.Open strSQL, strConn

Set adoRS.ActiveConnection = Nothing

Disconnected Recordset의 장점은 다음과 같습니다.

- 클라이언트 커서를 사용하며, 자유로운 데이터 액세스가 가능합니다.
- DB 연결을 끊은 상태에서 레코드셋 작업을 수행하므로 DB 서버의 자원(커서, 메모리, 네트워크 연결 등)을 점유하는 시간이 최소화됩니다.
- 끊긴 연결은 언제든지 다시 연결하여, 레코드셋에서 변경된 사항을 DB에 적용할 수 있습니다.
- 클라이언트 커서와 함께 DB 확장성(Scalability)에 큰 도움이 됩니다.

 

DBHelper에서는 기본적으로 Disconnected Recordset을 사용합니다.

 

2) 커서(Cursor)의 사용

ADO에서 지원하는 커서에는 크게 4가지 종류가 있습니다. 이러한 커서를 적절히 사용하면 애플리케이션의 성능을 향상시킬 있습니다.

 

종류

특징

비고

Forward-Only

MoveNext 가능

RecordCount, 페이징 사용 불가

나머지는 Static 동일

RecordCount 페이징이 필요 없는 경우 권장

가장 빠른 성능

Keyset

다른 사용자가 추가한 레코드는 없음

나머지는 Dynamic 동일

DB 부하가

Dynamic

레코드셋의 모든 기능 사용 가능

다른 사용자의 변경 내용을 모두 있음

DB 부하가 가장

성능이 가장 느림

Static

다른 사용자의 변경내용 볼수 없음

그외 레코드셋의 모든 기능 사용 가능

대부분의 경우에 권장

 

위에서 언급한 것처럼 대부분의 경우에는 Static 커서를 사용하는 것이 가장 적합합니다.

 

DBHelper에서는 Static 커서를 사용합니다.

 

3) RecordCount의 사용

Static / Keyset 커서를 사용하는 경우, 레코드셋의 RecordCount 속성을 사용할 수 있습니다. 이 속성은 편리하기는 하지만 신중하게 사용해야 합니다.
RecordCount 속성을 사용하는 경우 SQL 서버는 sp_cursoropen 저장 프로시저를 호출하여 커서를 열고 레코드들을 fetch 해 나가는데, RecordCount를 얻어내기 위해서는 전체 레코드를 최소한 1회 이상 fetch 해야 한다는 것을 의미합니다. 이 경우 불필요한 레코드 fetch가 증가될 수 있습니다.
성능이 문제가 되는 경우, RecordCount보다는 가급적이면 레코드의 개수를 Output 매개변수로반환해주는 SP를 사용하는 것을 권장합니다.

 

‘ Stored Procedure
CREATE PROCEDURE dbo.GetProducts
(  
  @RecordCount int OUTPUT
)
AS
  SELECT * FROM Products
  SELECT @@rowcount as  RecordCount
RETURN

 

‘ 호출 코드

Set adoCmd = CreateObject("ADODB.Command")
Set adoCmd.ActiveConnection = adoConn
adoCmd.CommandText = "GetProducts"         ‘sp 이름
adoCmd.CommandType = adCmdStoredProc       ‘또는 4
adoCmd.Parameters.Refresh

Set rs = adoCmd.Execute

rs.Close

 

‘output parameter는 레코드셋을 닫고 난 후에 접근 가능하다.
Set recordCount = adoCmd.Parameters("@RecordCount")

4) Client Cursor vs. Server Cursor

 

ADO는 디폴트로 서버 커서, 즉 데이터베이스에서 제공하는 커서를 사용합니다. 그러나, 서버 커서에는 다음과 같은 단점들이 존재합니다.

- 데이터베이스의 커서 자원을 사용합니다.
- 레코드들을 패치할 때마다 서버에 레코드 패치를 위한 네트워크 액세스가 일어납니다.

 

위의 부하를 줄이려면, 클라이언트 커서를 사용하면 됩니다. 클라이언트 커서를 사용하면 조회된 데이터는 모두 클라이언트(웹 서버)로 복사되고, 클라이언트(웹 서버)의 메모리에 저장됩니다. 그 이후 레코드 간의 이동은 클라이언트 메모리에 저장된 레코드셋 내에서 발생됩니다.
클라이언트 커서를 사용하려면 Connection 또는 Recordset 객체의 CursorLocation 속성 값을 adUseClient 상수 혹은 3으로 설정하면 됩니다.

클라이언트 커서를 사용하면 다음과 같은 장점이 있습니다.

- 클라이언트 커서를 사용하면 레코드셋의 커서가 자동적으로 static으로 고정됩니다.
  (단, 클라이언트로 복사하기 위해 DB에서 레코드셋을 읽을 때는 ForwardOnly 커서가 사

   용됩니다)
- 데이터베이스 서버의 자원 소비량이 상대적으로 낮습니다.
- 클라이언트와 데이터베이스 간의 네트워크 라운드 트립이 줄어듭니다.

클라이언트 커서를 사용하는 경우, DB의 자원과 부하는 줄어드는 대신 웹 서버의 자원을 사용하고, 웹 서버에 부하가 옮겨지게 됩니다. 따라서 만약 현재 DB 서버의 부하는 적은데 웹 서버의 부하가 매우 큰 상황이라면 사용하지 않는 것이 좋습니다.

 

DBHelper에서는 기본적으로 클라이언트 커서를 사용합니다.


5) 파라미터화된 쿼리(Parameterized Query)

동적인 쿼리를 작성하기 위해 일반적으로는 문자열 조합에 의한 쿼리를 사용하는 경우가 많습니다. 예를 들면 다음과 같겠죠.

 

strQuery = "SELECT * FROM Orders WHERE OrderDate >= ‘" & startDate & _
          "’ AND OrderDate < ‘" & endDate & "’"

rs.Open strQuery, adoConn

 

일단 따옴표(‘)를 빼먹기 쉽다는 문제는 제쳐 두더라도, 이 쿼리는 SQL 서버 내에서 수행될 때 startDate와 endDate의 값이 변경될 때마다 매번 컴파일 과정을 거쳐야 합니다. 불필요한 SQL 컴파일은 DB의 부하를 가중시키켜 성능 저하로 이어지게 됩니다.
이 문제를 피하려면 파라미터화된 쿼리(Parameterized Query)를 사용하는 것이 좋습니다. 보다시피 따옴표가 사라지고 ? 또는 @로 시작하는 파라미터가 추가되었습니다.

 

strQuery = "SELECT * FROM Orders WHERE OrderDate >= ? AND OrderDate < ?"
또는
strQuery = "SELECT * FROM Orders WHERE OrderDate >= @startDate AND OrderDate < _
@endDate"

 

매개변수를 가진 쿼리를 사용하는 경우에는 매개변수를 넣어주기 위해 반드시 Command 객체를 사용해야 합니다. (아래 예제 참조)

 


Set adoCmd = CreateObject("ADODB.Command")
Set adoCmd.ActiveConnection = adoConn
adoCmd.CommandText = strQuery
adoCmd.CommandType = adCmdText           ‘또는 1
adoCmd.Parameters.Append _
adoCmd.CreateParameter(
“@startDate”, adDate, adParamInput, , startDate)
adoCmd.Parameters.Append _
adoCmd.CreateParameter(
“@endDate”, adDate, adParamInput, , endDate)

rs.Open adoCmd           ‘Query 대신 Command 객체를 지정

 

이렇게 매개변수를 가진 쿼리를 실행하면, SQL Profiler에서 SQL배치가 아닌 RPC가 수행되어 더욱 속도가 빨라집니다. 또한 다음과 같이 매개변수화 되므로 startDate, endDate의 값이 변경되더라도 SQL 컴파일은 한번만 일어나게 됩니다.

 

exec sp_executesql N’SELECT * FROM Orders WHERE OrderDate >= @P1
AND OrderDate < @P2 ‘,
N’@P1 datetime,@P2 datetime’, ‘01 1 1995
12:00AM’, ‘01 1 1996 12:00AM’

 

매개변수를 가진 쿼리는 코드 가독성을 높여주고, 성능 면에서는 좋긴 하지만 코딩량이 다소 늘어난다는 단점이 있어서 귀차니즘(?) 때문에 안 쓰는 사람들이 많습니다. 모든 쿼리를 매개변수를 가진 쿼리로 작성할 필요는 없지만, 최소한 자주 수행되는 쿼리의 경우 이렇게 작성하면 DB의 부하를 줄이고 성능을 향상시킬 수 있습니다.

 

DBHelper에서는 이러한 코딩을 간편하게 할 수 있도록 지원합니다.

 

6) ADO 관련 상수

 

먼저 다음 코드를 봅시다.

Rs.Open SQL, Dbcon, 0, 1

ASP 코딩에 능숙한 사람은 알겠지만 0은 커서를 adForwardOnly, 1은 락을 ReadOnly로 지정하는 것입니다. 하지만, 위처럼 상수값을 숫자로만 지정하면 코드의 가독성이 떨어집니다. 그러므로 실제로는 다음과 같이 해주는 것이 이상적입니다.


Rs.Open SQL, Dbcon, adOpenForwardOnly , adLockReadOnly      


ADO에서는 위와 같은 상수를 사전에 정의한 파일을 제공합니다. 이 파일을 사용하기 위해서는 C:\Program Files\Common Files\System\ado에 있는 Adovbs.inc 파일을 include 해줘야 합니다.


<!--#include file="C:\Program Files\Common Files\System\ado\adovbs.inc" -->


그러나 include를 사용하면 그만큼 페이지 컴파일에 대한 부하가 발생해서 성능이 저하게 됩니다. 이를 피하기 위해서는 type library를 사용하면 되는데 각 페이지에 다음과 같이 선언하면 됩니다.


<!--METADATA TYPE= "typelib"  NAME= "ADODB Type Library"
      FILE="C:\Program Files\Common Files\SYSTEM\ADO\msado15.dll"  -->

이 코드를 아예 Global.asa에 추가하면 각 페이지에 추가할 필요없이 ADO 관련 상수를 마음대로 사용할 수 있습니다.

 

5. 튜닝 결과

4번 항목에서 제시된 기법들을 사용해서 DBHelper를 작성한 후, 이를 적용하도록 각 페이지를 수정하는 작업이 이루어졌습니다. 일부 쿼리는 SP 또는 파라미터화된 쿼리로 재작성되기도 했습니다. DB 튜닝과 함께 애플리케이션 튜닝을 병행한 결과는 어떻게 되었을까요?

 

예상했던 결과가 이루어졌습니다.


 

 

평균 CPU 사용량이 65%대이던 DB 서버는 31% 정도로 크게 감소했으며, 웹 서버는 20% 정도에서 30%로 사용량이 늘어나게 되었습니다. 이용자 수도 거의 비슷했으며 적용전, 적용후 각각 1달 가까이를 모니터링한 결과입니다.

이에 따른 예상 수치로 볼 때 S사는 현재 사용자가 2배로 늘어나도 감당할 수 있을 것이라는 새로운 Capacity를 가지게 되었습니다. 그에 따라 굳이 플랫폼을 변경하거나 하드웨어를 교체할 필요가 없게 됨으로써 시간과 비용을 절약할 수 있게 된 셈입니다. 따져보면 별다르게 한 것도 없는데 말이죠. ^^;;

 

여기까지가 장황한 튜닝기입니다. 허접한 녀석이지만 행여나 DBHelper를 써보시고 싶으신 분들은 이 글의 첫 머리에 있는 Taeyo 사이트에 가셔서 다운받으시면 됩니다.

 

그런데 DBHelper 썼는데 우리는 성능이 왜 개선 안되냐? 라고 돌 던지신다면 대략 낭패입니다. 예를 들어 DB 서버는 팽팽 놀고 웹 서버 부하는 큰데 DBHelper를 그대로 적용한다면 오히려 성능이 더 저하될 수도 있다는 것을 감안하셔야 할 것입니다. 이 경우는 오히려 DB 서버의 자원을 적극 활용하도록 DBHelper를 변경해서 써야 할 수도 있겠죠? 또한 이 코드를 보다 세련되게 잘 다듬어서 주시는 분들이 계시면 더욱 더 감사할 듯 합니다. ^^

 

p.s. DBHelper의 코드 내용에 대한 문의는 사절합니다. 솔직히.. 몇년전에 짠거라서 기억도 잘 안납니다. 참 무책임하지요? ㅎㅎㅎ