MSSQL을 사용 도중 복원을 하게 되면 자주 이런 현상이 나타났습니다.
원인은 아직 파악을 못했고 검색 결과 해결 방법을 찾았다.
- RESTORE 명령으로 복원 후 사용자 데이터베이스 '복원 중' 상태 -
해결방법은
RESTORE DATABASE DB명 WITH RECOVERY
MSSQL을 사용 도중 복원을 하게 되면 자주 이런 현상이 나타났습니다.
원인은 아직 파악을 못했고 검색 결과 해결 방법을 찾았다.
- RESTORE 명령으로 복원 후 사용자 데이터베이스 '복원 중' 상태 -
해결방법은
RESTORE DATABASE DB명 WITH RECOVERY
자료형 |
설명 |
범위 |
uint8 |
부호없는 8비트, 1바이트 정수 |
0 ~ 255 |
uint16 |
부호없는 16비트, 2바이트 정수 |
0 ~ 65535 |
uint32 |
부호없는 32비트, 4바이트 정수 |
0 ~ 4294967295 |
uint64 |
부호없는 64비트, 8바이트 정수 |
0 ~ 18446744073709551615 |
int8 |
부호있는 8비트, 1바이트 정수 |
-128 ~ 127 |
int16 |
부호있는 16비트, 2바이트 정수 |
-32768 ~ 32767 |
int32 |
부호있는 32비트, 4바이트 정수 |
-2147483648 ~ 2147483647 |
int64 |
부호있는 64비트, 8바이트 정수 |
-9223372036854775808 to 9223372036854775807 |
float32 |
IEEE-754 32비트 단정밀도 부동소수점, 7자리 정밀도 보장 |
|
float64 |
IEEE-754 64비트 배정밀도 부동소수점, 15자리 정밀도 보장 |
|
complex64 |
float32 크기의 실수부와 허수부로 된 복소수 |
|
complex128 |
float64 크기의 실수부와 허수부로 된 복소수 |
|
byte |
uint8과 크기가 동일, 바이트 단위로 저장할 때 사용 |
|
int32와 크기가 동일, 유니코드 문자 코드를 저장할 때 사용 |
|
|
uint |
32비트 시스템에서는 uint32, 64비트 시스템에서는 uint64 |
|
int |
32비트 시스템에서는 int32, 64비트 시스템에서는 int64 |
|
uintprt |
uint와 크기가 동일하며 포인터를 저장할 때 사용 |
|
[ 변수 선언 ]
키워드 변수명 자료형
var i int
var s string
선언과 동시에 초기화를 시켜주면 자료형을 생략 가능합니다.
var i = 10
var s = "string"
키워드 var와 자료형을 생략도 가능합니다.
i := 10
s := "string"
위의 내용을 응용해서 여러개 선언하는 법
var x, y int = 30, 50 // x = 30, y = 50
var x, y = 30, 50 // x = 30, y = 50
x, y := 30, 50
[ 변수 크기 ]
c언어의 sizeof 연산자처럼 변수의 크기 구하기 입니다.
크기는 바이트단위 입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package main import "fmt" import "unsafe" // Sizeof 함수를 사용하기 unsafe 패키지 사용 func main() { var num1 int8 = 1 var num2 int16 = 1 var num3 int32 = 1 var num4 int64 = 1 fmt.PrintIn(unsafe.Sizeof(num1)) // 1 fmt.PrintIn(unsafe.Sizeof(num2)) // 2 fmt.PrintIn(unsafe.Sizeof(num3)) // 4 fmt.PrintIn(unsaef.Sizeof(num4)) // 8 } | cs |
[ 문자열 ]
문자열 길이 구하기
len함수를 사용
1 2 3 4 5 6 | var s1 string = "한글" var s2 string = "Hello" len(s1) // 6 : UTF-8 인코딩의 바이트 길이이므로 6 len(s2) // 5 : 알파벳 5글자이므로 5 | cs |
[ 문자열 수정하기 ]
문자열의 문자를 직접적으로 수정할수 없습니다.
[ 상수 선언 ]
const 상수명 자료형 = 초기값
1 2 | const i int = 10 const s string = "STRING" | cs |
[ 열거형 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | const Sunday = 0 const Monday = 1 const Tueday = 2 const Wedday = 3 const Thuday = 4 const Friday = 5 const Satday = 6 // const () 키워드를 사용시 const를 반복하지 않아도 됩니다. const( Sunday = 0, Monday = 1, Tueday = 2, Wedday = 3, Thuday = 4, Friday = 5, Satday = 6 ) // 또는 iota를 사용하여 대입연산자를 생략 가능합니다. const( Sunday = iota, Monday, Theday, Wedday, Thuday, Friday, Satday ) | cs |
- 이번 챕터에는 간단하게 Go언어 설치와 IDE 설치하여 유명한 Hello World까지 진행하겠습니다.
- 윈도우 10을 기준으로 설치를 진행하겠습니다.
Go 버전은 1.7이며
IDE는 LiteIDE로 선정하였습니다.
비주얼스튜디오에 익숙해서 그쪽으로 플러그인을 찾아봤습니다.
2013까지 지원하는 버전이었습니다만... 제가 2015버전인 관계로 ... 일단 패쓰하였습니다.
2015 버전지원이 되면 저도 그쪽을 이용해보고 괜찮으면 그쪽으로 갈아탈 예정입니다.
=> 설치파일 https://golang.org/dl/
Microsoft Windows 버전을 다운로드 받습니다.
Next 신공후 마무리는 Finish!!!!
LiteIDE 설치파일 URL : https://sourceforge.net/projects/liteide/files/X30.2/
위 페이지로 이동을 하면
제일 상단에 있는 liteidex20.2.windows-qt4.zip을 다운로드 받습니다.
압축은 적당한 작업 폴더에 풀면 됩니다.
압축을 풀면 /bin/liteide.exe 를 실행하시면 됩니다.
우선 Go언어는 각종 패키지를 인터넷에서 다운받아서 사용됩니다. (추후에 자세히 다루겠습니다)
그래서 기준 경로가 있어야 됩니다.
기준이 되는 경로는 환경변수 설정을 통해서 설정하셔야 됩니다.
시스템 속성에 들어가시면
환경 변수 클릭!
GOPATH에 작업 폴더를 지정하시면 해당 패키지들이 해당 경로로 받아지게 됩니다.
간단하게 Hello, World를 출력하고 마무리하겠습니다.
파일을 생성후 아래 소스를 작성합니다.
F5를 누르면 빌드되어 실행파일이 만들어집니다.
( 빌드 환경설정은 다음기회에... )
빌드가 성공하면 아래에 Build Output에 아래와 같은 내용이 출력이 됩니다.
실행은 Ctrl + F5를 누르시면 됩니다.
이미 눈치채신 분은 있으시겠지만 비주얼스튜디오의 단축키와 비슷한 부분이 많습니다.
( 제가 다른 IDE로 작업을 많이 못해봤습니다. ;; )
내용이 많이 보이지만 실제 별거 없는 내용입니다.
앞으로 틈틈히 글을 올릴 생각입니다.
부족한 글솜씨에 인내심을 가지고 읽어주셔서 감사합니다.
인삿말
- 2007년에 클라이언트로 게임업계에 입사를 하였고 MMORPG (C++, 게임브리오엔진) 6년 -> 턴제 모바일게임(C#, 유니티엔진, 아파치, java, mysql) 1년6개월 -> 액션 모바일 (C#, 유니티엔진, Node.js, mssql) 1년10개월 을 제작 하였습니다.
서버에 대한 부족한 지식으로 빠르고 쉽게 웹서버를 만들수 있는 것을 찾던중 Node.js를 접하게 되었고
부족한 제가 정말 쉽게 원하는 기능을 만들었습니다.
물론 아직 Node.js에 대해 깊이 있게 다 이해했다고는 하지 못하지만 점점 Node.js에서 한계를 느꼈습니다.
1. 리눅스에 대한 이해도가 부족하여 윈도우 서버를 택했고 그로인해 Node.js에서의 강력한 모듈들을 사용하지 못한점
2. javascript의 성능과 오타에서 오는 스트레스, 컴파일언어에 대한 그리움
3. Node.js의 메인쓰레드밖에 활용 못한다는 점 (클러스터로 커버 가능은 함)
4. 초반에 잘못된 설계로 인해 callback헬... 추후 대규모 리빌딩.
5. 실시간 서버으로써의 성능 부족함 ( 언어로써의 성능 포함 )
6. 뭔가 새로운걸 찾고싶다는 욕구
+ 위에 나열한건 개인적은 견해이고 Node.js에 대한 잘못된 이해로 인해 잘못 사용하여 제 성능을 못 끌어 냈을수 있습니다. +
Node.js로 인해서 서버에 대해 많은 지식도 쌓고 CBT를 치르면서 부족한 점을 또한번 느끼게 되어 고마운 존재이기도 합니다.
C++로 서버를 제작을 할까 하는 와중에 Go언어를 알게 되었고 새로운걸 공부하고 싶다는 욕구에 시작하게 되었습니다.
앞으로 남길 글들은 사실 절 위한 메모와 같은 내용입니다.
부족하거나 이상한점 잘못된점이 있다면 알려주신다면 감사하겠습니다.
[ Go 언어 소개 ]
Go 언어는 구글이 개발한 프로그래밍 언어입니다.
2007년에 켄 톰슨, 롭 파이크, 로버트 그리즈머가 최초 설계를 시작했으며 2008년부터 본격적으로 개발되었습니다.
특히 C언어의 모체가 된 B언어와 유닉스의 개발자로 유명한 켄톰슨이 참여하여 큰 화제가 되었습니다.
Go 언어는 빠른 성능, 안정성, 편의성, 쉬운 프로그래밍을 목표로 개발되었습니다.
[ Go 언어 특징 ]
- 정적타입, 강 타입
- 컴파일언어
- 가비지 컬렉션
- 병행성
- 멀티코어 환경 지원
- 모듈화 및 패키지 시스템
- 빠른 컴파일 속도
참조 : 가장 빨리 만나는 Go 언어, https://golang.org/doc/
출처 : http://www.nextree.co.kr/p6753/
본글은 위 출처에서 퍼온 자료임을 알려드립니다.
불과 몇 년 되지 않은 학생 시절… 처음으로 UML을 접했고, UML의 기초적인 그리는 법과 사용법을 배웠습니다. 개인적으로 쉽지 않은 수업이었는데 그 중 가장 많이 사용되는 클래스 다이어그램에서 클래스간의 relationship(관계)가 제일 어려웠습니다.Generalization(일반화)과 Realization(실체화)은 명확하기 때문에 이해하는데 어려움이 없었고 Dependency(의존) 부터 조금 어려워 지더니 Association(연관)과 Aggregation(집합), Composition(합성) 3종 세트에 가서는 머리가 복잡해졌습니다. 특히 Aggregation과 Composition이 논리적으로 약하고 강한 집합이라는 차이는 알겠지만 ‘그래서 어떤 명확한 차이점이 발생하는 거지? 저걸 코드로 만들 때는 어떻게 만들어야 하는 거지?’라는 생각과 함께 잘 와 닿지 않았습니다.
그래서 2013년 9월에 진행 됐던 ’2013 넥스트리 신입사원 인큐베이션 세미나’에서 발표 주제를 UML 클래스 다이어그램으로 정하고 그 동안 배운 것들과 추가로 공부를 더한 것들로 발표를 했고, 많은 도움이 됐던 시간이었습니다. 세미나 발표 후 몇가지 내용에 대한 아쉬움이 있었는데, 이번 기회에 그 아쉬움과 부족했던 부분을 보완하여 글로 정리하게 되었습니다. UML 클래스 다이어그램의 기본적인 요소들과 클래스간의 관계, 그리고 제가 제일 어려웠던 이 관계들을 어떻게 코드로 나타내어야 할지에 대해서 썼으며 언어는 Java 기준으로 하였습니다. ’2013 신입사원 인큐베이션 세미나’에 대한 글도 Nextree 홈블로그에서 보실 수 있습니다.
1. UML
UML이란 Unified Modeling Language의 약자로 1997년 OMG(Object Management Group)에서 표준으로 채택한 통합모델링언어 입니다. 즉, 모델을 만드는 표준언어인 것입니다. 모델이란 것은 어떤 것을 실제로 만들 때 이렇게 만들면 잘 작동할지 미리 검증해 보는 것이며 실제 물건을 만드는 비용보다 비용이 훨씬 적을 경우에 모델을 만들어 설계를 검사합니다.
소프트웨어에서의 모델은 건축, 항공 등의 모델과는 좀 다른 면이 있습니다. 건물을 짓고, 항공기를 만드는 것과 설계를 그리고 만드는 것은 비용의 엄청난 차이가 있습니다. 하지만 UML 다이어그램을 그리며 모델을 만드는 일은 개발보다 비용이 적긴 하지만 훨씬 적게 드는 것이 아니며 때로는 오히려 개발보다 비용이 더 많이 들 수도 있습니다. 그래서 UML은 시험해 볼 구체적인 것이 있고, 그것을 코드로 시험해 보는 것보다 UML로 시험해 보는 쪽이 비용이 덜 들 때 주로 사용합니다. 이러한 목적으로 UML을 사용하는 유형에는 다음 3가지 정도가 있습니다.
UML을 그리는데 가장 좋은 도구는 종이와 펜이라는 말이 있듯이 습관적으로 만드는 게 아니라 필요에 의해 만드는 것이 가장 좋은 것 같습니다.
2. Class Diagram (클래스 다이어그램)
UML은 구조 다이어그램 7개, 행위 다이어그램 7개로 총 14종류의 다이어그램이 있습니다. 구조 다이어그램은 시스템의 개념, 관계 등의 측면에서 요소들을 나타내고 각 요소들의 정적인 면을 보기 위한 것이고 행위 다이어그램은 각 요소들 혹은 요소들간의 변화나 흐름, 주고받는 데이터 등의 동작을 보기 위한 것으로, 클래스 다이어그램은 구조 다이어그램에 해당합니다. 클래스 다이어그램은 클래스 내부의 정적인 내용이나 클래스 사이의 관계를 표기하는 다이어그램으로 시스템의 일부 또는 전체의 구조를 나타낼 수 있습니다. 클래스 다이어그램은 의존 관계를 명확히 보게 해주며, 순환 의존이 발생하는 지점을 찾아내서 어떻게 이 순환 고리를 깨는 것이 가장 좋은지 결정할 수 있게 해줍니다.
[그림 2] 목적 별 클래스 다이어그램
UML은 목적에 따라 다르게 사용되는데, 크게 3가지로 개념, 명세, 구현의 차원들 입니다.먼저 개념 차원의 UML은 문제 도메인의 구조를 나타내며 사람이 풀고자 하는 문제 도메인 안에 있는 개념과 추상적 개념을 기술하기 위한 것입니다. 이것은 소스코드와 관계가 그렇게 깊지 않으며 오히려 사람의 자연언어와 더 관련이 있습니다. 또한 의미론적(언어의 뜻을 규정하는) 규칙에 그다지 얽매이지 않으며, 따라서 의미하는 바도 모호하거나 해석에 따라 달라질 수 있는 부분이 존재합니다.
반면, 명세와 구현 차원의 UML은 소프트웨어의 설계 혹은 완성된 소프트웨어의 구현 설명 목적 등으로 사용하며 설계를 해서 소스코드로 바꾸거나 구현 된 소스코드를 설명하려고 사용하기 때문에 소스코드와 관계가 깊습니다. 이 두 차원의 클래스 다이어그램은 제약이 많아서 반드시 일정한 규칙과 의미론을 지켜야 합니다. 또한 모호성이 거의 없도록 하고 형식도 최대한 맞춰야 합니다.
앞으로 나올 내용들은 구조 다이어그램 중 하나인 클래스 다이어그램이며 그 중에서도 개념 차원은 배제하고 소스코드와 관계가 깊은 명세, 구현 차원에 해당하는 클래스 다이어그램만으로 한정 지어 소스코드와 어떻게 연관 되는지 이해해 보도록 하겠습니다. 따라서 개념 차원의 클래스 다이어그램과는 조금 다른 부분이 있을 수 있습니다.
3. 클래스 다이어그램의 요소(Element)
Class (클래스)
클래스는 보통 3개의 compartment(구획)으로 나누어 클래스의 이름, 속성, 기능을 표기합니다. 속성과 기능은 옵션으로 생략이 가능하지만 이름은 필수로 명시해야 합니다.
[그림 3] 클래스
클래스의 세부사항은 필드와 메서드의 Access modifier(접근제한자), 필드명(메서드명), 데이터타입, parameter(매개변수), 리턴 타입 등을 나타낼 수 있습니다. 클래스의 세부사항들을 상세하게 적는 것이 유용할 때도 있지만, UML 다이어그램은 필드나 메서드를 모두 선언하는 곳이 아니기 때문에 다이어그램을 그리는 목적에 필요한 것만 사용하는 것이 좋습니다. 추가로 보통 3개의 구획(compartment)을 사용 하지만 다른 미리 정의되거나 사용자 정의 된 모델 속성(비즈니스 룰, 책임, 처리 이벤트, 발생된 예외 등)을 나타내기 위한 추가 구획도 사용할 수 있다고 합니다.
Stereo Type (스테레오 타입)
스테레오 타입이란 UML에서 제공하는 기본 요소 외에 추가적인 확장요소를 나타내는 것으로 쌍 꺾쇠와 비슷하게 생긴 길러멧(guillemet, « ») 사이에 적습니다. 이 길러멧이란 기호는 쌍 꺾쇠와는 좀 다른 것으로 폰트 크기보다 작습니다. 종이나 화이트보드에 그릴 때는 상관없지만 공식적인 문서라면 이 기호를 구분해서 사용하는 것이 좋을 것 같습니다.
[그림 4] 스테레오 타입
위의 다이어그램은 인터페이스와 유틸리티 클래스를 표현하고 있으며 필드, 메소드 밑의 밑줄은 static(정적)필드 또는 메서드를, {readOnly}는 final 키워드를 사용하는 상수를 의미합니다. 스테레오 타입으로 많이 사용되는 것은 «interface», «utility», «abstract», «enumeration» 등이 있습니다.
Abstract Class/Method (추상 클래스 / 메서드)
추상클래스란 1개 이상의 메서드가 구현체가 없고 명세만 존재하는 클래스를 말합니다.
[그림 5] 추상클래스
추상 클래스의 이름과 메서드는 italic체나, {abstract} 프로퍼티를 사용하여 표기합니다. UML 툴에서는 italic체로 표기하는 것이 많지만 종이나 칠판에 그릴 때는 힘들게 italic체로 기울여서 적는 것 보다는 {abstract} 프로퍼티로 표기하는 것이 쉽고 명확할 것 같습니다.
또한 공식적인 것은 아니지만 스테레오타입을 사용하여 추상 클래스를 표기하기도 합니다.
4. 클래스간의 관계
클래스 다이어그램의 주 목적은 클래스간의 관계를 한눈에 쉽게 보고 의존 관계를 파악하는 것에 있습니다. 그렇기 때문에 클래스 다이어그램에서 가장 중요한 것이 클래스간의 관계입니다.
[그림 6] 클래스 관계 종류
위의 그림은 클래스간의 관계들의 종류와 표기법을 나타낸 것입니다. 이 외에 다른 표기법도 있습니다만 많이 사용된다고 생각하는 것들만 나타냈습니다.
Generalization (일반화)
Generalization은 슈퍼(부모)클래스와 서브(자식)클래스간의 Inheritance(상속) 관계를 나타냅니다. 여기서 Generalization이란 서브 클래스가 주체가 되어 서브 클래스를 슈퍼 클래스로 Generalize 하는 것을 말하고 반대의 개념은 슈퍼 클래스를 서브 클래스로 Specialize(구체화) 하는 것입니다. 상속은 슈퍼 클래스의 필드 및 메서드를 사용하며 구체화 하여 필드 및 메서드를 추가 하거나 필요에 따라 메서드를 overriding(오버라이딩) 하여 재정의 합니다. 또는 슈퍼 클래스가 추상 클래스인 경우에는 인터페이스의 메서드 구현과 같이 추상 메서드를 반드시 오버라이딩 하여 구현하여야 합니다.
[그림 7] Generalization
위와 같이 표기법은 클래스 사이에 실선을 연결하고 슈퍼 클래스 쪽에 비어 있는 삼각형으로 나타내고 자바에서는 extends 키워드를 사용하여 상속을 구현합니다.
Realization (실체화)
Realization은 interface의 spec(명세, 정의)만 있는 메서드를 오버라이딩 하여 실제 기능으로 구현 하는 것을 말합니다.
[그림 8] Realization
Realization을 나타내는 표기법은 2가지가 있습니다. 첫 번째는 인터페이스를 클래스처럼 표기하고 스테레오 타입 «interface»를 추가합니다. 그리고 인터페이스와 클래스 사이의 Realize 관계는 점선과 인터페이스 쪽의 비어있는 삼각형으로 연결합니다. 두 번째는 인터페이스를 원으로 표기하고 인터페이스의 이름을 명시합니다. 그리고 인터페이스와 클래스 사이의 관계는 실선으로 연결합니다.
자바에서는 위와 같이 implements 키워드를 사용하여 인터페이스를 구현합니다.
Dependency (의존)
Dependency는 클래스 다이어그램에서 일반적으로 제일 많이 사용되는 관계로서, 어떤 클래스가 다른 클래스를 참조하는 것을 말합니다.
[그림 9] Dependency
위의 그림은 자바에서 참조하는 형태에 대해 코드를 보여주고 있습니다. 참조의 형태는 메서드 내에서 대상 클래스의 객체 생성, 객체 사용, 메서드 호출, 객체 리턴, 매개변수로 해당 객체를 받는 것 등을 말하며 해당 객체의 참조를 계속 유지하지는 않습니다.
[그림 10] Dependency Stereo Type
추가로 위와 같이 스테레오 타입으로 어떠한 목적의 Dependency인지 의미를 명확히 명시 할 수도 있는데 Dependency의 목적 또는 형태가 중요할 경우 사용할 수도 있을 것 같습니다.
Association (연관), Directed Association(방향성 있는 연관)
클래스 다이어그램에서의 Association은 보통 다른 객체의 참조를 가지는 필드를 의미합니다. 아래 클래스 다이어그램은 두 가지 형태의 Association을 나타내고 있습니다.
[그림 11] Assocication
첫 번째 다이어그램은 일반적인 Association으로 단지 실선 하나로 클래스를 연결하여 표기하고 두 번째 다이어그램은 Directed Association으로 클래스를 실선으로 연결 후 실선 끝에 화살표를 추가합니다. Association과 Directed Association의 차이는 화살표가 의미하는 navigability(방향성)인데 이것에 따라 참조 하는 쪽과 참조 당하는 쪽을 구분합니다. 두 번째 다이어그램은 User에서 Address 쪽으로 화살표가 있으므로 User가 Address를 참조하는 것을 의미합니다. Navigability가 없는 Association은 명시되지 않은 것으로 User가 Address를 참조할 수도, Address가 User를 참조할 수도, 또는 둘 다일 수도 있는 것을 의미합니다. 화살표 옆에 있는 –addresses는 roleName(역할명)을 나타내고 Address가 User 클래스에서 참조될 때 어떤 역할을 가지고 있는지를 의미합니다.
*는 Multiplicity(개수)을 나타내는데 대상 클래스의 가질 수 있는 인스턴스 개수 범위를 의미합니다. 0…1 과 같이 점으로 구분하여 앞에 값은 최소값, 뒤에 값은 최대값을 의미하는데 *은 0…*과 같은 의미로 객체가 없을 수도 있고 또는 수가 정해지지 않은 여러 개일 수도 있다는 것을 의미합니다. 이전에는 Multiplicity가 아닌 Cardinality로 불렸는데 “특정 집합 또는 다른 그룹에 있는 요소의 수”라는 Cardinality의 사전적 의미가 실제 인스턴스의 수가 아닌 가질 수 있는 범위를 지정하는 클래스 다이어그램에서의 의미에 적합하지 않다는 이유로 바뀌었습니다.
세 번째의 다이어그램은 두 번째의 다이어그램과 비슷한 의미를 가지고 있지만 다른 형태인 속성 표기법으로 나타낸 것입니다. 여기서 보는 바와 같이 roleName은 보통 클래스의 필드명이 됩니다. 속성 표기법이 두 번째 클래스 다이어그램과 조금 다른 점은 여러 개의 객체에 대한 Container(컨테이너)가 List라는 것까지 알려주고 있습니다.
그럼 두 번째와 세 번째의 다이어그램이 완전히 동일한 의미를 가지게 하려면 어떻게 해야 할까요?
[그림 12] Association Class
위와 같이 Association Class(연관클래스)를 사용하여 어떤 종류의 컨테이너 클래스가 사용되는지 까지 나타낼 수 있습니다. 하지만 사실 특이한 클래스도 아니고 자바에서 기본으로 제공되는 List를 저렇게 표기하는건 조금 귀찮은 일일 수 있을 것 같습니다. 그래서 스테레오 타입으로 표기할 수도 있습니다. 이로써 [그림11] 세 번째 다이어그램의 속성 표기법으로 표현된 것과 모든 의미가 같아졌습니다. 보통은 클래스의 속성이 기본 제공 클래스가 아니거나 중요 또는 강조하고 싶을 때 Association 관계로 나타냅니다. Association Class는 조금 다른 의미로도 사용될 수 있습니다. 예를 들어 학생과 수강과목 클래스가 Association 관계를 가지고 있는데 단순 Association 관계가 아니라 각 관계마다 해당 과목의 학점이라는 속성이 필요하다면 어떻게 나타낼 수 있을까요? 이럴 때도 Association Class를 사용하여 나타낼 수 있습니다.
[그림 13] Association Class
물론 grade라는 값을 Subject 클래스 자체의 속성으로 할 수도 있지만 Subject의 속성이라기 보다는 Student와 Subject 사이의 관계에 대한 속성이라는 관점에서 위의 다이어그램처럼 Association Class로 나타낼 수 있습니다.
[그림 14] Association Class Vs Association
또한 [그림13]의 Association Class를 풀어서 위처럼 Association 관계만으로도 나타낼 수 있습니다. [그림13]은 Student와 Subject의 관계를 나타내고 싶은데 그 관계에 대한 속성값으로 Grade가 있는 것이고 [그림14]는 단순 3개 클래스를 Association 관계로 나타낸 것처럼 의미는 조금 다를 수 있으나 구현되는 코드는 같을 것입니다.
[그림 15] Association Class Code
Aggregation (Shared Aggregation, 집합)
Aggregation은 Shared Aggregation이라고도 하며 Composition(Composite Aggregation)과 함께 Association 관계를 조금 더 특수하게 나타낸 것으로 whole(전체)와 part(부분)의 관계를 나타냅니다. Association은 집합이라는 의미를 내포하고 있지 않지만 Aggregation은 집합이라는 의미를 가지고 있습니다.
[그림 16] Aggregation
표기법은 위와 같이 whole과 part를 실선으로 연결 후 whole쪽에 비어있는 다이아몬드를 표기합니다. Part쪽에는 화살표를 명시하여도 되고 명시하지 않아도 됩니다. Aggregation의 다이아몬드가 이미 navigability의 방향을 표현하고 있기 때문입니다. 그런데 코드를 보시면 위에서 보았던 Association의 코드와 똑같습니다. Association과 Aggregation은 집합이라는 개념적인 차이는 있지만 코드에서는 이 차이를 구분하기 힘듭니다.
[그림 17] UML Aggreagtion
출처: OMG Unified Modeling Language Superstructure 2.4.1
위와 같이 UML은 집합이라는 개념 외에 명확한 Aggregation의 정의를 제공하지 않습니다. 그래서 여러 프로그래머나 분석가, 설계사가 Aggregation 관계에 대해 자기 나름의 정의를 내렸기 때문에 혼란이 생겼고 Aggregation은 사용하지 않는 것이 좋다고 합니다. 저도 이에 동의 하는 바이지만….. 아직도 논란이 되고 있는 부분이고 정확한 답을 내기는 어려울 것 같습니다.그리고 도서 “The Object Primer: Agile Model-Driven Development with UML 2.0(저자 Scott W. Ambler)”과 “UML 실전에서는 이것만 쓴다(저자 Robert C. Martin)”에 UML 2.0에서는 위의 문제 때문에 Aggregation이 제외 되었다는 말이 있습니다. 그래서 근거를 찾기 위해 이곳 저곳 찾아본 결과 처음엔 제외 되었다가 커뮤니티의 강력한 항의로 다시 들어왔다고 합니다. 실제로도 UML 1.x 버전에 비해 2.x 버전에는 Aggregation에 대한 내용이 많이 사라지긴 했지만 몇 군데 남아 있는 걸 확인했습니다.
[그림 18] Aggregation Dropped
출처: www.coderanch.com/t/154620/java-Architect-SCEA/certification/Association-Aggregation
Composition (Composite Aggregation, 합성)
Composition(또는 Composite Aggregation)도 Aggregation과 비슷하게 whole(전체)와 part(부분)의 집합 관계를 나타내지만 개념적으로 Aggregation보다 더 강한 집합을 의미합니다.
[그림 19] Composition
Composition의 표기법 또한 위와 같이 Aggregation과 비슷하지만 다이아몬드의 내부가 채워져 있다는 점만 다릅니다. 그럼 Composition의 개념과 코드에서는 Aggregation과 어떤 차이가 있는지 보겠습니다. Composition은 Aggregation보다 강한 집합이라고 했습니다. 여기서 강한 집합이란 part가 whole에 종속적이어서 part가 whole의 소유입니다. 반면 Aggregation은 part가 whole에 대해 독립적이어서 whole이 part를 빌려 쓰는 것과 비슷합니다. 이러한 의미 때문에 Aggregation과는 다르게 명확하게 나타나는 점이 있습니다.
첫 번째의 whole 인스턴스가 part 인스턴스의 전체 수명을 책임진다는 의미는 다음과 같습니다.
두 번째의 part에 해당하는 인스턴스는 공유 될 수 없다는 의미를 먼저 보겠습니다.
[그림 20] Shallow Copy
위의 예제는 클래스 다이어그램이 아닌 객체 다이어그램으로 [그림19]를 객체로 표현한 것입니다. 참조변수 userA가 참조하고 있는 user 객체를 clone하여 clonedUser 객체를 만들고 참조변수 userB에서 참조하고 있습니다. user객체는 제대로 복사가 됐지만 user객체 안에서 참조하고 있는 address는 clonedUser 객체도 똑같이 참조하고 있습니다. 이것을 shallow copy(얕은 복사)라고 하며 이 경우에 part에 해당하는 address 객체가 공유 된 것입니다. 또한 첫 번째 조건의 의미 중 whole 인스턴스가 복사되면 part인스턴스도 복사되어야 한다는 조건도 충족시키지 못했습니다.
[그림 21] Deep Copy Object Diagram
위의 다이어그램에서는 user 객체가 복사되어 clonedUser 객체가 생성될 때 user 객체가 참조하여 가지고 있는 address 객체 또한 같이 복사 되어 clonedUser 객체는 새로운 clonedAddress 객체를 참조하여 가지고 있습니다.
[그림 22] Deep Copy Code
Aggregation 관계와 Composition 관계를 UML 툴에서 그린 후 Code Generation을 하면 똑같은 코드가 생성됩니다. 하지만 Composition에서는 개발자가 구현해야 할 부분이 몇 가지 있습니다. 위에서 본 part에 해당하는 인스턴스가 공유되지 않게 하기 위한 Deep Copy 구현과 part를 가지는 whole 인스턴스가 part 인스턴스의 수명 전체를 책임져야 한다는 것에 따라 whole 클래스의 생성자 또는 기타 메서드 내에서 part 인스턴스를 생성해야 하고 외부에서 part 객체를 생성하지 못하도록 whole 클래스에는 part 인스턴스에 대한 setter가 있으면 안됩니다. 다른 언어에서는 생명주기와 관련된 다른 추가적인 것도 있겠지만 자바에서의 객체 소멸은 Garbage Collector가 수행하므로 part 인스턴스의 소멸은 신경쓰지 않아도 됩니다.
5. 마치며
이로써 클래스 다이어그램의 주요 요소들과 관계들이 소스코드와 어떻게 연관되는지를 살펴 봤습니다. 우선 많은 용어들에 대해 영문발음 그대로 한글로 표기하는 것들은 처음에만 영문 표기 후 한글로 표기하였고 영문 용어가 해석에 따라 달라질 수 있는 것들(예: Association->연관)은 최대한 영문 그대로 표기하였습니다.
또한 UML에서 attribute(속성), operation(기능)이라고 부르는 것들이 자바에서는 filed(필드), method(메서드)라 불리우기 때문에 의미는 비슷하지만 사용 관점에 따라 분리하여 사용한 것들도 있으며 초급 개발자로서 UML에 관련된 내용을 쓰려니 혹시 내가 잘못 알고 있는 것은 아닐까 조심스러워서 UML 스펙 문서를 많이 찾아가며 최대한 표준에 맞게 쓰려고 하였습니다.
저는 처음에 클래스 다이어그램을 공부하면서 개념적으로 들었을 때는 이해가 갈듯 말듯 하다가 코드를 보면서 아 이런 거구나 하며 그나마 조금 더 이해가 갔던 기억이 납니다. 설계를 하시는 분들이 아닌 저와 같이 이제 막 개발자의 길로 들어서신 초급 개발자 분들이 설계 다이어그램을 보며 어떤 식으로 이해를 해야 하고 어떻게 코드를 만들어야 할지 조금이라도 도움이 되었으면 합니다.
그리고… 개인적인 내용입니다만 아직 많이 모자라지만 1년동안 많은 도움을 주셨던, 특히나 UML과 설계와 관련된 많은 지식을 전해주신 제 멘토 김현오 선임께 감사하단 말씀을 제대로 못 드린 것 같아 여기서 감사의 말씀을 드리고 싶습니다..^^
감사합니다.
OS: Windows7,32bit or 64bit (SP1 이상)
개발 환경: Microsoft .Net 4.0 , DirectX SDK June 2010., Visual Studio 2010 이후
이 레벨 에디터를 개발에 사용한 것은 PS3『The Last of Us』(Naughty Dog), PS4의『Killzone: Shadow Fall』(Guerrilla Game)등에서 사용된 오픈소스 프레임워크 「Authoring Tools Framework」.
에디터를 사용하려면 Visual Studio 2010에서 빌드할 필요가 있다.
Authoring Tools Framework (ATF)는 Windows 머신 상에서 툴을 만들기 위해 C#/.NET 컴포넌트로 소니의 퍼스트 파티 게임 스튜디오의 대부분에서 많은 커스텀 툴을 만들 때 사용되고 있다.
Naughty Dog 의『The Last of Us』 의 레벨 에디터 및 세이더 에디터, Guerrilla Games 의 KILLZONE 프랜차이즈 (PS4 의 런칭 타이틀『KILLZONE SHADOWFALL』도 포함) 의 시퀸스 에디터 , SCE 산타모니카 스튜디오의 아니메이션 블렌딩 툴, SCE 벤드 스튜디오의 레벨 에디터, Quantic Dream의 비주얼 스테이트 머신 에디터, 사운드 편집 툴 등이 사례이다.
2006년를 시작으로 소니 월드 와이드 스튜디오 중심으로 툴 그룹에 의해 계속 개발하고 있다.
ATF는 GitHub 에서 공개 되고 있는 오픈 소스 프로젝트이다.
출처: http://3dnchu.com/archives/sce-leveleditor/
안녕하세요. 소심비형입니다. Visual Studio Community 2015와 Xamarin을 이용하여 모바일 크로스 플랫폼 환경을 구성하는 방법에 대해서 알아보도록 하겠습니다. 크로스 플랫폼이다보니 Android와 Windows Phone, iOS에 대한 앱 개발 라이센스와 회원 가입이 모두 되어 있어야 하고, 유료 등록이 되어 있어야 합니다. 개발자 라이센스를 등록하지 않았다면 몇가지 제약 사항이 따르게 됩니다.
Xamarin(자마린)이란?
모바일 크로스 플랫폼 환경을 제공하는 상용 3th party 제품으로, 모바일 앱(iOS, Android, Window Mobile)을 C#으로 만들 수 있습니다. MonoTouch 6.0 이후로 자마린으로 이름이 변경되었습니다.
시작...
비주얼 스튜디오 커뮤니티 2015에서 새 프로젝트를 선택합니다. (이전 버전의 경우 탬플릿이 없습니다.)
만약, Visual Studio Community 2015를 설치할 때 커스텀 설치로 "Xamarin (3th Party)"를 선택했다면 같이 설치가 되어 있을겁니다.
아직 템플릿이 추가되어 있지 않으므로 이름은 아무렇게나 지어도 됩니다. 저는 MyFirstApp으로 지정했습니다.
"Download Xamarin"을 클릭하세요! 아래 링크를 통해 직접 다운로드 후 설치해도 됩니다.
[ 다운로드 ]
자마린을 다운로드 하기 위한 기본적인 정보를 입력한 후 "Download Xamarin for Visual Studio" 클릭합니다. (회원 가입 후 로그인하면 다운로드 받을 수 있습니다.)
아래와 같이 입력한 후 다운로드를 클릭하세요! (이름과 이메일은 알아서 적당히 적으세요-_-; "소심비형" 적지 마시구요.)
다운로드 받은 XamarinInstaller.exe를 실행합니다.
현재 운영 체제의 보안이 낮게 설정되어 있다면 이 창은 나타나지 않을수도 있습니다. 실행을 클릭하세요.
Continue 클릭!
자마린을 설치하기 위해 필요한 필수 구성 요소도 같이 설치된다고 알려줍니다. Next를 클릭하세요.
라이센스에 동의하고 Next 클릭!
안드로이드 SDK도 같이 설치됩니다. Next를 클릭하세요.
Visual Studio가 켜져 있으면 나타나는 화면입니다. 아래 "Forec Visual Studio to quit."를 클릭하여 강제 종료하고 Next를 클릭하세요.
요구 사항을 확인하고 Next를 클릭하세요.
Java 라이센스에 동의하고 Next 클릭!
Android 라이센스에 동의하고 또 Next 클릭!
설치가 진행중입니다. 설치가 멈춘듯이 보일지도 모르지만, 계속 기다리다 보면 설치가 이어서 진행됩니다.
이제 맥에도 자마린을 설치합니다. 대부분 위의 내용과 동일합니다. 맥에서도 아래와 같이 설치가 진행됩니다.
윈도우와 맥에 자마린이 모두 설치가 되었다면, 맥에서 환경 설정을 변경해야 합니다. 먼저, 윈도우에서 맥으로 로그인할 수 있도록 원격 로그인을 허용합니다. Spotlight 검색(Control + Space)에서 시스템 환경설정(system preferences)을 입력하고 검색되는 응용 프로그램을 실행하세요. 아래 그림처럼 공유를 선택하세요.
원격 로그인에 체크하고, 모든 사용자를 선택합니다.
맥에 Xcode가 설치되지 않았다면, 아래 링크에서 다운로드 받은 후 설치하세요.
[ 다운로드 ]
설치가 완료되면 Spotlight 검색(Control + Space)에 Xamarin을 입력하여 Xamarin Studio를 실행하세요.
상단의 Xamarin Studio > 환경 설정... > SDK 위치 > Apple을 선택합니다. 아래 그림처럼 Apple SDK가 정상적으로 바인딩 되어 있는지 확인하세요. 만약, X표시라면 우측의 찾아보기를 클릭한 후 Xcode.app를 직접 지정하면 됩니다.
※ 간혹, beta가 설치되어 있다면 Xcode-beta.app로 되어 있을 수 있습니다.
Spotlight 검색(Control + Space)에 Xcode를 입력한 후 실행하세요.
상단의 Xcode > Preferences... > Downloads로 이동하고, 컴포넌트에서 시뮬레이터를 다운로드 받습니다. 모두 받아도 상관은 없지만, 저의 경우 하드 용량이 부족하여 하나만 설치했습니다-_-;
만약, 맥북 프로 레티나에서 가상 환경(Parallels, VMware)으로 구성 하였다면 아래와 같이 가상 환경의 설정을 변경해야 합니다. 만약, Windows Phone Emulator 또는 Android AVD를 구동하려면 가상 환경에서 Hyper-V 사용을 선택해야 합니다. 아래 그림과 같이 "중첩 가상화 사용"에 체크하세요.
지금은 해결이 되었는지 확인하진 못했지만, 맥북 프로 레티나에서 가상 환경으로 윈도우를 사용하는 경우, iOS 시뮬레이터가 정상 동작하지 않는 문제가 있습니다. 아래 그림처럼 비디오 메모리를 설정하고, "Retina 해상도 활성화"를 사용하지 않아야 합니다.
이제 모든 설정을 마쳤으므로 윈도우와 맥을 재부팅하세요.
Visual Studio Community 2015를 실행하고, 새 프로젝트를 선택합니다. Visual C# > iOS > iPhone의 "WebView App (iPhone)" 탬플릿을 선택하고 이름은 MyFirstWebApp으로 지정하고 확인을 클릭하세요.
프로젝트가 생성되면 Visual Studio의 도구 > 옵션을 실행하세요. Xamarin > iOS Settings를 선택하고, 아래 그림과 같이 "Find Xamarin Mac Agent"를 클릭합니다.
아래 그림의 "Add Mac..."을 클릭합니다.
맥의 컴퓨터 이름 또는 아이피를 입력하고 "Add"를 클릭하세요.
맥의 계정정보를 입력하고 "Login"을 클릭합니다.
아래 그림처럼 맥이 연결됩니다.
옵션에 Xamarin Mac Agent가 등록되었습니다.
Visual Studio의 상단에 Machine에서 iPhoneSimulator를 선택하세요.
에뮬레이터를 선택합니다. 저는 iPhone 6s Plus iOS 9.1을 선택했습니다.
만약, 아이폰을 가지고 있고, 맥에 연결되어 있다면 자신의 아이폰에서 테스트 할 수도 있습니다. 자신의 아이폰에서 테스트 하려면 애플 개발자 센터에 등록되어 있어야하고 인증키가 등록되어 있어야 합니다.
F5를 눌러서 실행하면 원격으로 연결된 Mac에서 아이폰 에뮬레이터가 실행되고, 윈도우의 Visual Studio 프로젝트가 표시됩니다.
웹앱은 기본적으로 MVC의 Razor 엔진으로 구성되고, 간단한 모델과 뷰가 포함되어 있습니다.
안드로이드 가상 환경을 구성하려면 안드로이드용 Visual Studio 에뮬레이터를 설치해야 합니다. 아래 링크를 통해 다운로드 후 설치하세요.
[ 다운로드 ]
웹앱 프로젝트를 안드로이드 가상 환경에서 실행한 화면입니다.
디자인은 다르지만, iOS와 동작은 같습니다.
Android, iOS와 다르게 윈도우폰은 WPF로 되어 있습니다.
이렇게 해서 윈도우 환경의 Visual Studio에서 iPhone과 Android, Windows Phone 앱을 개발하기 위한 환경을 구축하는 방법에 대해서 알아보았습니다. 이외에도 여러가지 부가적인 요소가 있지만 기본 구성에 영향을 주지는 않기 때문에 여기에서 다루지는 않았습니다. 사업 영역을 모바일로 확대하려는 회사에서 자마린을 도입했거나, 검토중인 회사들이 많아진듯 보입니다. 솔직히 Objective C와 Android Java를 배워서 개발하는 비용보다 자마린을 도입하는게 더 저렴할수도 있습니다. 그렇더라도 플랫폼에 따른 제약이나 특별한 기능을 구현하기 위해서는 어느정도 각각의 플랫폼에 대한 학습은 병행되어야 합니다. 저도 이제 막 공부를 시작한 입장에서 어떤 방향이 좋다 나쁘다를 말할 처지는 아니구요. 혼자서 모바일 앱을 빠르게 개발하고 배포해야 하기에 자마린을 선택한 것뿐입니다.
개인적인 프로젝트를 진행하면서 틈틈히 관련 내용을 작성할 예정이긴 한데... 항상 시간이 없다는게 문제죠-_-;
다음 시간에...
출처 : http://blog.naver.com/kikky22/140040666763
ORCLE이 정말 좋은 RDB라는 것을 알게 하는 것이 바로 페이징 기법일거라 생각되네요.
MySQL도 내부적으로 페이징이 가능한 쿼리를 지원해주지만 MSSQL은 최근 2005버전까지도... 좋은 페이징 기법을 소개하지 못하고 있는 것 같네요. 성능 좋은 페이징 기법이 공개된 것이 있기도 하지만... 초심자에게 쉽지 않은 쿼리들인 것 같습니다.
이에 조금 쉽게... 어떻게 하면 성능이 향상되는지를 설명해 보려고 합니다.
아래의 내용은 온라인상에서 바로 작성하는 내용이고 맞춤법등이 틀릴 수 있기 때문에 copy해서 사용하지 마시기 바랍니다.
개념을 잡는 정도로 활용하시면 좋을 것 같습니다.
MS SQL의 페이징 기법의 키는 TOP 키워드입니다.
#1. TOP과 클러스터드 인덱스
SELECT TOP 10 ID, subject, contents FROM TBL
이 쿼리는 누구나 알고 있는 쿼리입니다. 여기서 중요한 것이 TOP 10 입니다. 상위 10개만 갖고 오겠다는 뜻입니다.
MSSQL은 내용저장을 클러스터드 인덱스 순으로 저장을 하게 됩니다. 만약 ID를 PK로 지정하셨거나 따로 클러스터드 인덱스로써 ID를 지정해 놓으셨다면 ID순으로 자동으로 정렬이 되어 상위 10개만 가져오게 됩니다.
기본키는 반드시 설정할 필요는 없습니다. 다만 레코드를 구분하는 아이디값을 대게의 경우 기본키로 놓게 되는데요.
사실 기본키가 성능에 있어서의 의미는 없다고 봅니다.(확인된 바 없음)
기본키는 자동으로 인덱스 컬럼이 된다는게 의미가 있겠죠. 그것도 테이블당 딱 하나 사용할 수 있는 클러스터드 인덱스로 자동 설정됩니다. 헌데 문제는 ASC로 설정된다는 것입니다.
웹페이지에서 최근 글의 경우는 대부분 DESC로 정렬합니다. 즉 최근 글을 먼저 표시해주지요. PK로 만들더라도 꼭 ID를 DESC로 인덱스하도록 만들어야 합니다.
바로 이 유일 인덱스 컬럼이 성능을 좌우하는 핵입니다.
초심자의 경우 인덱스의 중요성을 넘기는 경우가 많은데요. PK가 중요한 것이 아니라 정렬을 원하는 컬럼을 클러스터드 인덱스로 만들어 놓는 것이 성능에 가장 중요합니다.(레코드 수가 늘 수록 엄청난 성능 향상이 있습니다.)
팁) TOP 10 PERCENT라는 키워드도 가능합니다. 말 그대로 전체의 10%만 가져온다는 것입니다. 쓸모가 많은 팁이라 생각되네요.
#2. 가장 많이 쓰이는 페이징 쿼리
SELECT TOP 10 ID, subject, contents FROM TBL where ID not in (SELECT TOP 현재페이진 이전까지의 모든 게시물 수 ID FROM TBL order by ID DESC) order by DESC
참 좋은 쿼리입니다. MS SQL에서 나올 수 있는 가장 간결하고 좋은 쿼리가 아닌가 싶습니다.
저역시 작은 규모의 게시판 종류는 무조건 이 쿼리를 이용합니다. 유지보수가 편하기 때문입니다. 누구나 쉽게 알아 볼 수 있기 때문에 제가 도저히 못 봐줄 유지보수 프로젝트라면 다른 사람이 대신할 수 있는 쿼리이기 때문에... 이 쿼리를 즐겨사용합니다.
다만 이 쿼리에는 조건이 하나 붙습니다.
사용자들이 100페이징 이하(게시물 수로 2000개 이하정도)의 글을 되도록 조회한다.
이 쿼리는 2만건 이하의 테이블에 적당하다고 생각됩니다.
1페이지라고 하면 성능이 최고가 되며
2페이지라면 not in 안의 쿼리문에 의해 한페이지가 10개의 글이라고 가정하면 10개를 일단 불러 들이게 됩니다. 제거를 위해서죠.
3페이지라면 20개를 불러들여서 제거를 해야 하겠고
4페이지라면 30개를...
그럼 100페이지라면 990개의 글을 읽어 들여야 겠군요. 990개를 먼저 불러 들이는 것이 문제입니다.
가장 심플한 쿼리이지만 DB에 어느정도의 부하를 주는 쿼리라는 것을 알 수 있습니다.
개인적으로 레코드셋종류의 객체에 내용을 불러오는 쿼리는 0.1초 이전에 끝나야 한다고 생각됩니다. 물론 검색이 들어가면 이야기가 달라지지만 기본적인 형태(아무런 검색이 없는 경우)에서는 0.1초 이하에서 OPEN을 끝내는 것이 좋다고 생각되네요.
#3. ORDER BY문
아시다시피 ORDER BY문은 정렬의 조건입니다. 위 쿼리의 경우 ORDER BY ID DESC이니깐 ID에 대해 내림차순으로 정렬하겠네요. 사실 ORDER BY 문은 안써주는 것이 성능에 가장 좋습니다.
만약 ID를 클러스터드 인덱스로 지정해 놨다면 안써도 될 것 같습니다. 클러스터드 인덱스를 내림차순으로 지정해 놨다면 ORDER BY ID DESC는 성능에 전혀 영향을 미치지 않습니다. 가끔 MSSQL에서 서브쿼리를 썼을 경우 원하는 값을 리턴하지 않습니다. 이유는 모르겠습니다. 서브쿼리문을 가져오는 방법에서 더 빨리 가져오려고 하는 그 부분에서 나오는 문제일거라 생각되네요.
클러스터드 인덱스로 지정했을 경우 ORDER BY ID DESC는 되도록이면 넣으시는게 좋습니다. 정확성을 위해서!;
#4. 성능저하 요소 SELECT COUNT(*) FROM TBL
NOT IN 쿼리보다 심플한 페이징 쿼리는 MSSQL에서 없는 것 같습니다. 개발자 입장에서 프로그래밍하기도 정말 쉬운 쿼리입니다. 현재 페이지 번호만 넘겨주면 모든 것이 가능합니다. 가장 큰 장점이 바로 개발하기 편하다는 것이 겠고, 사용자의 웹접근 액션과도 상당히 잘 맞아 떨어집니다. 사람들은 10페이지 이상은 잘 보지 않으려는 경향이 있기 때문입니다.
NOT IN 쿼리는 생각보다 좋은 쿼리라는 것을 일단 말씀 드립니다. 단 조건은 INDEX를 잘 설정해줬다는 조건이 붙습니다.
게시판 등을 개발할 때 전체 게시물 수를 구해오는데 가장 많이 쓰는 쿼리문이 SELECT COUNT(*) FROM TBL입니다. 페이지 바로 가기 버튼을 위해서도 필요하고 게시물 번호를 붙히는 데도 쓰이기 때문에 쓰는 경우가 많습니다.
헌데 이 쿼리문 속도가 상당히 늦습니다. 100만건을 조회할 경우 1초가 넘어가 버리는 무식한 쿼리입니다. 야야~ 그럼 IDEX행을 가져와봐... 라고 하실 것 같습니다. SELECT COUNT(ID) FROM TBL ... 허나 애석하게 속도가 똑같습니다.
그리고 COUNT함수는 가능하면 (*)를 사용하시기 바랍니다. 이것이 정확한 방법입니다. COUNT(*)에서 속도향상을 위한 방법은 솔직히 말씀드려서 없습니다.
가장 좋은 방법은 테이블 하나를 만들어서 데이타 입력/삭제시마다 업데이트 하면서 게시물 수를 저장해 놓는 방법입니다. MSSQL 내에서는 트리거라는 기능을 제공합니다. INPUT/DELETE 시 UPDATE TBL_SETTING set TBL_COUNT = xxx 뭐 이런 식으로 짜 놓으면 되겠죠.
전체 게시물 수를 가져올 때는 되도록이면 트리거를 쓰거나 프로그램을 통해 정보를 저장하는 테이블에 업데이트하고 이 자료를 페이징시 가져오는 것이 성능을 위한 좋은 방법입니다.
1만건 이하라면 COUNT(*)를 쓰던 NOT IN을 쓰던 별 지장이 없다는 게 제 생각입니다. 고로, 자꾸 써먹어도 좋은 쿼리 들임을 일단 알려드립니다.
#5 성능향상에 가장 좋은 방법
1000만건을 테스트 해보지는 않았지만, 1페이지와 100만 페이지가 같은(해보진 않았죠^^)-혹은 비슷한- 성능을 보이는 쿼리는 다름 아닌 NOT IN보다 훨씬 더 간결한 쿼리입니다.
SELECT TOP 11 ID, subject, contents FROM TBL where ID <= 현재페이지 최상위 ID (order by ID DESC)
이 쿼리에서 가장 중요한 것은 ID가 클러스터드 인덱스로 ID를 설정하고 내림차순으로 지정되어 있어야 한다는 것입니다.
아무리 많은 글들도 0.1초안에 해결될만한 가장 성능이 좋은 쿼리문입니다. 동접자수 엄청나고 글 수가 많다면 이방법 이외의 방법은 사용하지 마시기 바랍니다.
허나 장점이 있으면 단점도 있습니다. 이 쿼리를 사용할 경우 ID값에 바로 접근하긴하기 때문에
이전 1 2 3 4 5 6 7 8 9 10 다음 <- 이와 같은 구성이 불가능하다는 것입니다.
그래서 TOP 10이 아닌 11을 사용한 것입니다. 1부터 10까지 구성은 힘들지만 다음페이지 버튼은 가능하기 때문입니다. 갯수가 11개면 다음 페이지가 있다는 이야기가 되며, 다음페이지의 최상위 ID값도 가져올 수 있게 됩니다.
어쨌거나 위 쿼리는 성능에 있어서는 더이상 좋을 수 없는 쿼리입니다. 분명 글이 많고 사용자 액션이 단순한 사이트라면 반드시 고려해보셔야 할 쿼리입니다. 이전 페이지 구현은 프로그램적으로 머리를 좀 굴려야 할 부분이긴 합니다.
어짜피 다음 페이지 버튼을 눌러야만 가능하니깐 이전 페이지의 ID값은 무조건 가지고 갈 수 있습니다. POST방식으로 이전 페이지 정보를 계속 넘기는 방법도 괜찮은 방법일 것입니다.
SELECT TOP 10 ID FROM TBL where ID > 현재페이지 최상위 ID order by ID ASC 를 어쩔 수 없이 쓰는 것도 한 방법이겠구요. 그래도 다른 쿼리들보다는 빠른 방식이니깐요. <- 이건 저도 테스트 해보진 않았습니다.
#6. 사용자 편의성도 좀 생각해 보자
대부분 웹사이트에서는 NOT IN쿼리가 좋은 방법입니다. 사용자 편의성에 있어서 좋은 선택이니깐요.
이전 1 2 3 4 5 6 7 8 9 10 다음 <- 이게 얼마나 편한 방법입니까^^; 그리고 사람들은 10페이지 이상 조회를 거의 하지 않기도 합니다.
성능을 생각한다면 #5번의 방법이 정말 좋은 방법이지요. 다만 사용자 편의를 위한 인터페이스 구현은 사실상 불가능 합니다. 이전 페이지 구현도 쉽지 않죠.
목표가 생겼습니다.
이전 1 2 3 4 5 6 7 8 9 10 다음
이 기능을 한번 구현해 보죠. 약간 성능 저하가 있더라도... 전체 NOT IN보다는 훨씬 더 빠르게 한다는 목표를 가지고...
일단 쿼리를 하나 보죠.
SELECT TOP pageSize*10+1 ID from TBL where ID <= 1페이지 11페이지 21페이지 등 각 1페이지의 처음 ID
이 쿼리는 페이지 바로가기 버튼 구현을 위한 쿼리입니다.
페이지 사이즈가 10개라고 하면 101개를 가져옵니다. 101개면 너무 많지 않냐 하겠지만 적은 갯수입니다.^^
컬럼이 하나밖에 없기 때문에 속도 저하가 거의 없는 쿼리죠.
이 결과를 가지고 1 2 3 4 5 6 7 8 9 10 다음 버튼 구현이 가능합니다. 이전 버튼 구현은 역시 약간 복잡하죠?
PageInfo = rs.getrows() 등의 좋은 메소드 등을 통해 배열로 만든 후 이 기능을 구현하는 것이 가장 좋은 방법일거라 생각됩니다.
SELECT TOP 10 ID, subject, contents from TBL where ID not in(SELECT TOP pageSize*(현재페이지의한자리숫자-1 / 0일때는 10) ID from TBL where ID <= 페이지 11페이지 21페이지 등 각 1페이지의 처음 ID order by ID DESC) and ID <= 페이지 11페이지 21페이지 등 각 1페이지의 처음 ID order by ID DESC
이 쿼리는 실제로 글을 뿌려주는 쿼리입니다. NOT IN이 쓰였네요. 하지만 10페이지 단위로 끊어서 10페이지 글 내에서 NOT IN을 사용하기 때문에 항상 빠른 속도를 내줄 수 있는 쿼리입니다.
페이지당 글 수가 아무리 많아도 100개 이하가 대부분이기 때문에 10페이지 단위로 끊는다고 해도 1000개의 글 내에서 모든 작업이 이루어지기 때문에 성능 저하는 거의(아예) 없다고 보시면 됩니다. 1000개정도 레코드는 아무것도 아니지요.
다만 걸리는 것은 페이지 바로 가기 버튼을 구현하기 위해 비슷한 쿼리를 두번 날렸기 때문에 두배의 비용이 든다는 거겠지요.
#7. 검색에 대한 이야기
검색 속도를 위한 가장 좋은 방법은 고가의 검색 엔진을 사용하는 것입니다. 검색엔진에 DB를 설정하고 URL 저장 방법만 설정해 놓고 스케쥴링만 해 놓으면 검색엔진은 알아서 DB를 검색하고 고쳐진 값에 대해서 URL 링크를 인덱싱해 놓습니다.
속도도 빠르고 한글의 경우 형태소 분석기를 통해 별에 별 검색도 가능하며 서비스 측면에서는 하일라이트 생성기등을 통해 사용자 편의성을 제공해주고... 뭐... 문제는 쩐이군요^^;
MSSQL에서 우리는 like '%xxx%' 검색을 많이 활용하게 됩니다.
SELECT ID, subject, contents from TBL where subject like '%xxx%'
이 쿼리는 xxx를 가지는 모든 subject 컬럼에 대해 검색을 하게 됩니다. 그럼 어떻게 해야 할까요. 넵~ 인덱스를 설정해야 합니다. subject에 대해서 넌클러스터드 인덱스를 설정해 주어야 합니다.
subject 는 varchar(255)형입니다. 그렇기 때문에 인덱스 설정이 가능합니다.
-> 몇년만에 수정합니다. 잘못된 정보네요^^; like 'xxx%'일때만 인덱스 타요~ 참고하시구요. 너무 예전에 쓴 글인데 여전히 이렇게 읽으실 줄이야. 에구구구... 이 이야기는 추후 다시 해야 할 것 같네요.
그럼 contents like '%xxx%'는?
헌데 contents가 text형이거나 varchar(max) (이건 2005에서 지원)라면?...
불행히도 인덱스를 줄수가 없습니다. MSSQL은 그다지 많은 인덱스 공간을 지원해주지 않습니다.
이경우 가능하면 input쪽에 varchar(900)정도 만큼만 글을 입력하도록 제한하거나 varchar(900)을 몇개 더 만들어서 DB저장시 나누어서 넣어주는게 좋습니다.
편법이고 지저분한 방법입니다.^^; 그래도 뭐 속도 향상이 있다면야... 모두들 어쩔 수 없이 text형도 검색을 하지만, 좋은 방법이 아닙니다. 글이 1만개만 넘어가다 상당한 부하가 걸릴 거라 생각됩니다.
넌클러스터드 인덱스만이라도 걸려 있다면, 성능은 무척 좋아집니다.
하지만 너무 방법이 지저분 하네요.
더좋은 방법이 있겠죠? MSSQL은 이런 경우를 위해 풀텍스트검색서비스를 지원합니다. varchar(MAX)나 text형 등을 시중의 검색엔진과 비슷한 방식으로 인덱싱하고 검색할 수 있는 방법은 제공합니다. 속도가 그렇게 좋지는 못합니다만... 형태소 분석기도 들어 있고 유사어 검색도 가능하고 정확도 정렬도 가능합니다. 다만 문제는 속도가 생각처럼 나오지는 않는 다는 것입니다. 특히 정확도 정렬을 위한 정렬의 경우 100만건 이상으로 테스트시 1초가 넘어가더군요.
그리고 MSSQL 2000에서 한글은 제대로 지원되지 않았습니다. 2005에서 한글 지원이 되는데... 실제로 띄어쓰기를 하지 않아도 검색이 되는 정도를 확인하였습니다. 동의어 검색도 가능하다고 하는데... 저역시 많은 테스트가 필요할 것 같습니다.
2000에서는 전혀 안쓰는 기능이었지만, 2005에서는 충분히 활용가치가 있을 것 같네요. 다만 호스팅 업체에서 이 기능을 지원하지 않는 다는 것이 가장 큰 문제입니다.^^; 인덱싱 속도는 꽤 빠르나 하드디스크를 많이 차지하기 때문에, 그리고 인덱싱시 꽤 부하를 주기 때문에 지원하지 않는 것 같으며, 2000의 경우 한글 인덱싱 자체가 잘 안되기 때문에 지원을 하지 않는 것 같습니다.
다만 MSSQL 2005라면 프로젝트에 충분히 쓸 수 있을 것도 같습니다. 제가 이번에 활용해보도록 하겠습니다.
상용검색엔진에 비하면 못하겠지만 어느정도 흉내를 내주고 CONTAINS(TABLE)/ FREETEXT(TABLE)등의 4개의 함수를 통해 SQL쿼리문 내에서 사용하기 때문에 개발하기가 수월합니다.
풀텍스트 검색엔진에 대한 이야기는 또 다음에 계속 하도록 하겠습니다.
정리;
속도 향상을 위해 가장 중요한 것은 바로 INDEX 설정!;
글 가져다 나르는 것을 금지합니다.
ps. 2011년 MS SQL 2005 이상이면, .net에서 LINQ가 만들어주는 SQL 문이 있는데요.
rownum() 함수 써서 하는게 속도가 좋네요.
참고하시고 시간 날때 정리할꼐요
[출처] 페이징 성능 향상 기법 MSSQL 쿼리|작성자 웃자웃자
통상적으로 테이블 로우수를 가지고 올때 아래와 같이 많이 사용 할 것이다.
select count(1) from 테이블명
테이블 로우수가 얼마되지 않은 자료를 가지고 올때는 위와같이 사용해도 특별히 문제점은 없다.
하지만 대용량으로 가면갈수록 전체 테이블에 로우수를 확인하는데도 초단위 이상에 시간이 소요가 된다.
덩치가 좀 되는 테이블 로우수는 어떻게 취하는게 효율적일까? 그 해답은 아래와 같다.
SELECT DISTINCT MAX(idx.rows)
FROM SYSINDEXES as idx INNER JOIN SYSOBJECTS AS obj
ON (idx.id = obj.id)
WHERE (obj.type = 'U') AND (obj.name = '테이블명')
쿼리를 보면 알겠지만 시스템 테이블을 활용하여 Row Count를 취하는 방법이다.
비교된 결과물이 있어야 화아악~ 와 닿겠죠잉~ ^^
제가 보유하고 있는 테이블 중에 Row Count가 54,602,856 인것을 예로 들면
먼저 흔히들 사용하는 select count(1) from 테이블명 쿼리로 하였을 때 결과다
결과값을 가지고 오는 4분 37초가 소요가 되었다.
반면
SELECT DISTINCT MAX(idx.rows)
FROM SYSINDEXES as idx INNER JOIN SYSOBJECTS AS obj
ON (idx.id = obj.id)
WHERE (obj.type = 'U') AND (obj.name = '테이블명')
서프라이즈~ ^^ 이 얼마나 놀라운가 시스템 테이블에 정보를 이용하여 실행과 함께 결과물이 나왔다.
이것을 실행결과로 비교해보면 100:0 에 실행 계획이 나온다.
나 역시 ms sql에서 테이블 로우수를 빨리 취하는법에 대해 알고는 있었지만 사용은 하지 않는다.
왜? 위에 쿼리보다 아래쿼리가 기니까~ ㅋ
하지만 대용량 서버에서 로우수를 취할 때는 유용하게 사용될 수 있을것이다.
더불어 해당 DB에 모든 테이블에 로우수를 가지고 오는 방법으로는 아래 쿼리를 사용하면 될것이다.
select obj.name, max(idx.rows)
from sysindexes as idx
inner join sysobjects as obj on (idx.id = obj.id)
where (obj.type = 'U')
group by obj.name
참고로 sysobject와 sysindexes layout 정보를 첨부해본다.
이런 된장~ 포스팅을 하고 검색을 좀 해보니 프로시저로 제공이 된다.. 뜨벌~
execute sp_tables_info_rowset '테이블명'
나 지금 모한거니? ㅠ,.ㅜ
[sysobject]
열 이름 | 데이터 형식 | 설명 | ||
---|---|---|---|---|
name | sysname | 개체 이름 | ||
id | int | 개체 ID | ||
xtype | char(2) | 개체 유형입니다. 다음 개체 유형 중 하나일 수 있습니다. AF = 집계 함수(CLR) C = CHECK 제약 조건 D = 기본값 또는 DEFAULT 제약 조건 F = FOREIGN KEY 제약 조건 L = 로그 FN = 스칼라 함수 FS = 어셈블리(CLR) 스칼라 함수 FT = 어셈블리(CLR) 테이블 반환 함수 IF = 인라인 테이블 함수 IT = 내부 테이블 P = 저장 프로시저 PC = 어셈블리(CLR) 저장 프로시저 PK = PRIMARY KEY 제약 조건(K 유형) RF = 복제 필터 저장 프로시저 S = 시스템 테이블 SN = 동의어 SQ = 서비스 큐 TA = 어셈블리(CLR) DML 트리거 TF = 테이블 함수 TR = SQL DML 트리거 TT = 테이블 유형 U = 사용자 테이블 UQ = UNIQUE 제약 조건(K 유형) V = 뷰 X = 확장 저장 프로시저 | ||
uid | smallint | 개체 소유자의 스키마 ID입니다. 이전 버전의 SQL Server에서 업그레이드한 데이터베이스의 경우 스키마 ID는 소유자의 사용자 ID와 동일합니다.
사용자 및 역할 수가 32,767을 초과하는 경우 오버플로되거나 NULL을 반환합니다. 자세한 내용은 | ||
info | smallint | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
status | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
base_schema_ver | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
replinfo | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
parent_obj | int | 부모 개체의 개체 ID입니다. 예를 들어 트리거 또는 제약 조건인 경우 테이블의 ID입니다. | ||
crdate | datetime | 개체를 만든 날짜입니다. | ||
ftcatid | smallint | 전체 텍스트 인덱싱을 위해 등록된 모든 사용자 테이블의 경우 전체 텍스트 카탈로그 식별자이며, 등록되지 않은 모든 사용자 테이블의 경우 0입니다. | ||
schema_ver | int | 테이블의 스키마가 변경될 때마다 증가하는 버전 번호입니다. 항상 0을 반환합니다. | ||
stats_schema_ver | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
type | char(2) | 개체 유형입니다. 다음 값 중 하나를 사용할 수 있습니다. AF = 집계 함수(CLR) C = CHECK 제약 조건 D = 기본값 또는 DEFAULT 제약 조건 F = FOREIGN KEY 제약 조건 FN = 스칼라 함수 FS = 어셈블리(CLR) 스칼라 함수 FT = 어셈블리(CLR) 테이블 반환 함수 IF = 인라인 테이블 함수 IT = 내부 테이블 K = PRIMARY KEY 또는 UNIQUE 제약 조건 L = 로그 P = 저장 프로시저 PC = 어셈블리(CLR) 저장 프로시저 R = 규칙 RF = 복제 필터 저장 프로시저 S = 시스템 테이블 SN = 동의어 SQ = 서비스 큐 TA = 어셈블리(CLR) DML 트리거 TF = 테이블 함수 TR = SQL DML 트리거 TT = 테이블 유형 U = 사용자 테이블 V = 뷰 X = 확장 저장 프로시저 | ||
userstat | smallint | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
sysstat | smallint | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
indexdel | smallint | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
refdate | datetime | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
version | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
deltrig | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
instrig | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
updtrig | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
seltrig | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. | ||
category | int | 게시, 제약 조건 및 ID에 사용됩니다. | ||
cache | smallint | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. |
[sysindexes]
열 이름 | 데이터 형식 | 설명 |
---|---|---|
id | int | 인덱스가 속한 테이블의 ID입니다. |
status | int | 시스템 상태 정보입니다. 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. |
first | binary(6) | 첫 페이지 또는 루트 페이지에 대한 포인터입니다. indid가 0일 경우 사용되지 않습니다. NULL = indid가 1보다 큰 경우 인덱스가 분할됩니다. NULL = indid가 0 또는 1일 때 테이블이 분할됩니다. |
indid | smallint | 인덱스의 ID입니다. 0 = 힙 1 = 클러스터형 인덱스 >1 = 비클러스터형 인덱스 |
root | binary(6) | indid >= 1인 경우 root는 루트 페이지에 대한 포인터입니다. indid가 0일 경우 사용되지 않습니다. NULL = indid가 1보다 큰 경우 인덱스가 분할됩니다. NULL = indid가 0 또는 1일 때 테이블이 분할됩니다. |
minlen | smallint | 행의 최대 크기입니다. |
keycnt | smallint | 키 수입니다. |
groupid | smallint | 개체가 만들어진 파일 그룹의 ID입니다. NULL = indid가 1보다 큰 경우 인덱스가 분할됩니다. NULL = indid가 0 또는 1일 때 테이블이 분할됩니다. |
dpages | int | indid = 0 또는 indid = 1인 경우 dpages는 사용한 데이터 페이지의 수입니다. indid가 1보다 작은 경우 dpages는 사용한 인덱스 페이지의 수입니다. 0 = indid가 1보다 큰 경우 인덱스가 분할됩니다. 0 = indid가 0 또는 1인 경우 테이블이 분할됩니다. 행 오버플로가 발생할 경우 정확한 결과가 반환되지 않습니다. |
reserved | int | indid = 0 또는 indid = 1인 경우 reserved는 모든 인덱스 및 테이블 데이터에 할당된 페이지의 수입니다. indid가 1보다 작은 경우 reserved는 인덱스에 할당된 페이지의 수입니다. 0 = indid가 1보다 큰 경우 인덱스가 분할됩니다. 0 = indid가 0 또는 1인 경우 테이블이 분할됩니다. 행 오버플로가 발생할 경우 정확한 결과가 반환되지 않습니다. |
used | int | indid = 0 또는 indid = 1인 경우 used는 모든 인덱스 및 테이블 데이터용으로 사용된 총 페이지의 수입니다. indid가 1보다 작은 경우 used는 인덱스용으로 사용된 페이지의 수입니다. 0 = indid가 1보다 큰 경우 인덱스가 분할됩니다. 0 = indid가 0 또는 1인 경우 테이블이 분할됩니다. 행 오버플로가 발생할 경우 정확한 결과가 반환되지 않습니다. |
rowcnt | bigint | indid = 0 및 indid = 1을 기준으로 하는 데이터 수준 행 개수입니다. 0 = indid가 1보다 큰 경우 인덱스가 분할됩니다. 0 = indid가 0 또는 1인 경우 테이블이 분할됩니다. |
rowmodctr | int | 테이블에 대해 통계를 마지막으로 업데이트한 이후에 삽입, 삭제 또는 업데이트된 행의 총 수를 셉니다. 0 = indid가 1보다 큰 경우 인덱스가 분할됩니다. 0 = indid가 0 또는 1인 경우 테이블이 분할됩니다. SQL Server 2005 이상 버전에서 rowmodctr은 이전 버전과 완전히 호환되지는 않습니다. 자세한 내용은 주의를 참조하십시오. |
xmaxlen | smallint | 행의 최대 크기입니다. |
maxirow | smallint | 리프가 아닌 인덱스 행의 최대 크기입니다. SQL Server 2005 이상 버전에서 maxirow는 이전 버전과 완전히 호환되지는 않습니다. |
OrigFillFactor | tinyint | 인덱스가 만들어질 때 사용되는 원래 채우기 비율 값입니다. 이 값은 유지 관리되지 않지만 인덱스를 다시 만들어야 하거나 사용한 채우기 비율 값을 기억할 수 없는 경우에 유용합니다. |
StatVersion | tinyint | 0을 반환합니다. 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. |
reserved2 | int | 0을 반환합니다. 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. |
FirstIAM | binary(6) | NULL = 인덱스가 분할됩니다. 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. |
impid | smallint | 인덱스 구현 플래그입니다. 0을 반환합니다. 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. |
lockflags | smallint | 인덱스에 대해 고려된 잠금 세분성을 제약하는 데 사용합니다. 예를 들어 잠금 비용을 최소화하기 위해 일반적으로 읽기 전용인 조회 테이블을 테이블 수준의 잠금만 수행하도록 설정할 수 있습니다. |
pgmodctr | int | 0을 반환합니다. 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. |
keys | varbinary(816) | 인덱스 키를 구성하는 열의 열 ID 목록입니다. NULL을 반환합니다. 인덱스 키 열을 표시하려면 |
name | sysname | 인덱스 또는 통계의 이름입니다. indid가 0인 경우 NULL을 반환합니다. 응용 프로그램을 수정하여 NULL 힙 이름을 찾습니다. |
statblob | image | 통계 BLOB(Binary Large Object)입니다. NULL을 반환합니다. |
maxlen | int | 정보를 제공하기 위해서만 확인됩니다. 지원되지 않습니다. 향후 호환성은 보장되지 않습니다. |
rows | int | indid = 0 및 indid = 1을 기준으로 하는 데이터 수준 행 개수이며 indid가 1보다 작은 경우에 값이 반복됩니다. |
[출처] ms-sql 테이블 레코드 수 빨리 취하기|작성자 땅쿠