출처:http://process3.blog.me/20021963684?Redirect=Log


[STL & MFC Collection 사용상 주의]
-여러 스레드에서 읽는 것은 안전하다.
-여러 스레드에서 각각 다른 컨테이너(컬렉션)에 쓰는것은 안전하다


[위 두 가지 경우 이외에는 전부 안전하지 않다. (모두 동기화(lock)을 걸어주어야 함) ]
-삽입 ,삭제, 조회를 하는 모든 경우에 동기화
-반복자를 수행하는 전부 동기화

[연속 메모리 기반, 노드 메모리기반 STL 컨테이너 차이점을 확실히 알고 사용한다]
Posted by 패스맨

댓글을 달아 주세요

출처 http://minjang.egloos.com/2254472

물론 고수님들에겐 쉬운 문제지만 다음 구조체에서 char data[1]의 역할이 무엇인지 생각 해봅시다.

typedef struct tagWHATTHE {
int data1;
int data2;
char data[1];
} WHATTHE;

모르시는 분들은 최소 1분 정도 생각을 해봅시다.



그래도 잘 모르겠으면 약간의 힌트:

typedef struct tagWHATTHE {
int size;
int type;
char data[1];
} WHATTHE;



char data[1]의 역할은

난생 처음 이런 구조체를 보면 data[1] 변수가 도대체 어떤 의미인지 감을 잡기 힘들다. 왜 이런 변수가 쓰이는지는 직접 예제 코드를 보는 것이 가장 좋을 것 같다.

typedef struct tagHEADER {
int size;
int type;
char data[1];
} HEADER;

// int data_length, int* data;
HEADER* hd = (HEADER*)malloc(sizeof(HEADER) + data_length);
hd->size = sizeof(HEADER) + data_length;
hd->type = 0;
memcpy(hd->data, data, data_length);
fwrite(hd, 1, hd->size, file_handle);

한 마디로 char data[1]의 의미는 길이가 정해지지 않은 데이터를 담기 위한 일종의 더미 변수라고 보면 된다. 예에서도 있듯이 이런 코딩 테크닉은 어떤 데이터의 헤더를 표현할 때 많이 등장한다. 메모리 덩어리를 할당 받고 그것을 이 헤더 타입으로 캐스팅을 하면 앞 부분은 헤더가 놓이고 바로 뒤에 갖고 싶은 가변 길이 데이터를 쉽게 이을 수 있다. 윈도우 프로그래밍을 해보신 분이라면 아마 이런 것을 자주 봤을 것이다. 예를 들면:

typedef struct _RGNDATAHEADER {
DWORD dwSize;
DWORD iType;
DWORD nCount;
DWORD nRgnSize;
RECT rcBound;
} RGNDATAHEADER;

typedef struct _RGNDATA {
RGNDATAHEADER rdh;
char Buffer[1];
} RGNDATA;

RGN이라는 그래픽에서 그리는 영역을 지정하는 클리핑 객체를 담는 자료구조다. RGNDATA에 채워질 데이터가 몇 개나 올지 알 수 없으므로 이렇게 하였다. 또, 대표적인 비트맵 파일 관련 구조체도 빼놓을 수 없다.

typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;

배열 크기가 여기는 [1]인데 [0]으로 둬도 사실 문제 없다. 그리고 소켓 프로그래밍할 때 보게 되는 hostent에도 이제는 과거 호환성 때문에만 남았지만 크기가 0인 배열을 볼 수 있다. 그런데 보통 크기 0인 배열을 선언하면 컴파일러가 워닝을 띄운다. 그래서 C99 표준에는 flexible array member라고 해서 맨 마지막 구조체 변수의 선언이 char data[] 처럼 될 수 있도록 하기도 한다.

도대체 왜?

그렇다면 왜 이렇게 했을까? 보다 직관적으로 코드를 만든다면 아래처럼 쓸 수도 있다.

typedef struct tagHEADER {
int size;
int type;
char* data;
} HEADER;

HEADER* hd = (HEADER*)malloc(sizeof(HEADER));
hd->size = 1024;
hd->type = 0;
hd->data = (char*)malloc(hd.size);
...

그러나 이 접근은 단점이 있다. 위에서 예를 들었듯이 이 자료구조를 파일에 쓴다고 하면 헤더 부분 따로 그리고 data 영역을 따로 두 번에 걸쳐 파일 쓰기를 해야 한다. 결국 이 말은 이 자료구조에 접근하려면 헤더 한번, 실제 한번, 즉 두 번의 참조가 필요하다는 이야기다.

여기서 쪼잔하게 따지면 위 코드는 데이터 참조의 지역성(locality)이 줄어들어 캐시 미스를 한번 더 유발할 수 있는 단점도 있다. 요즘 프로세서들 캐시가 수 메가 바이트니 이 정도 괜찮다라는 생각을 함부로 하지 말자. 정말 성능이 중요한 프로그램은 이런 사소한 지역성 차이에서 오는 차이를 결코 무시할 수 없다. 비슷한 예로 “구조체의 배열(Array of Structure)” 이냐 “배열의 구조체(Structure of Array)”라는 문제도 있다 (우리말과 영어의 어순이 반대라 이거 이름이 참 헷갈린다). 간단한 예를 보면..

구조체의 배열(Array of Structure, AoS):

struct {
double x;
double y;
double z;
} vector[4];

배열의 구조체(Structure of Array, SoA):

struct {
double x[4];
double y[4];
double z[4];
} vector_set;

각각 상황에 따라 적절히 선택해서 골라야 한다. 사소해 보이지만 경우에 따라 큰 성능 차이가 나타날 수 있다.

AoS 같은 접근은 루프 한 순회에서 모든 원소들이 접근될 때 유리하다. vector[i]을 읽으면 일단 i번 째 x, y, z는 모두 캐시에 올라오기 때문이다. 반면 원소는 3개인데 루프에서 고작 x원소만 접근 된다면? 이 vector 배열이 매우 크다면 손실은 심각하다. 그럴 때는 SoA 구조가 바람직하다. 그 외에도 사소한 영향을 더 생각할 수 있지만 생각보다 글이 길어져서 이쯤에서 그만..

한줄요약: char data[1]; 같은 것이 보여도 쫄지 맙시다.

 

Posted by 패스맨

댓글을 달아 주세요


출처 :

http://www.sqlworld.pe.kr



1. 테스트를 위한 임시 테이블 만들기와 데이터 추가하기

예전의 테스트 처럼 sqlworld 데이터베이스를 이용하여 실제 상황을 재현해 보도록 하겠습니다. 현재 sqlworld 데이터베이스의 옵션은 다음과 같습니다.

o 데이터베이스 복구모델 : 최대
o 자동 축소기능 : 사용안함

다음 [그림 1]은 현재 sqlworld의 데이터베이스와 로그 사이즈를 보여줍니다.


[그림 1]

우선 현재의 sqlworld 데이터베이스를 백업 받도록 하겠습니다.(모든 백업의 기본은 전체 백업입니다)

USE Master
GO

BACKUP DATABASE sqlworld TO DISK = 'E:\Data\sqlworld.bak'

1) 테이블 만들기

다음과 같이 테스트 테이블 Test_Log를 만들도록 하겠습니다.

USE sqlworld
GO

CREATE TABLE Test_Log
(
col1 int PRIMARY KEY,
col2 char(1000)
)

다음과 같이 스크립트를 이용해서 레코드를 추가하도록 하겠습니다.

SET NOCOUNT ON
GO

DECLARE @num int
SET @num = 1
WHILE @num < 5001
BEGIN
INSERT INTO Test_Log VALUES(@num, REPLICATE('A',1000))
SET @num = @num + 1
END

위 작업을 통해서 오천개 정도의 레코드가 Test_Log 테이블에 추가되었습니다. 이로 인하여 sqlworld 데이터 사이즈와 로그 사이즈가 증가했습니다. 아래 [그림 2]가 그 내용을 확인해주고 있습니다.


[그림2]

만일 sqlworld 데이터베이스 복구 모델이 '단순' 이었다면 위와 같은 작업이 완료가 되면 로그가 자동으로 제거되어 [그림 2] 처럼 로그 사이즈가 증가하지 않을 것입니다.(이 내용이 잘 이해되지 않으면 바로 이전의 강좌를 다시한번 읽어보시기 바랍니다)

2) 데이터를 변경하여 데이터와 로그 사이즈 증가시키기

다음과 같이 데이터를 변경하고 삭제하여 로그 사이즈를 증가시켜 보겠습니다.

UPDATE Test_Log Set col2 = REPLICATE('B',1000) WHERE col1 < 1000
GO
DELETE FROM Test_Log WHERE col1 < 2000
GO
DELETE FROM Test_Log WHERE col1 < 4000

위 작업을 수행하니 Test_Log 테이블의 데이터 변경에 대한 로그와삭제에 대한 로그가 증가함에 따라 sqlworld 데이터베이스의 사이즈는 다음 [그림 3]과 같이 변하였습니다.


[그림3]

로그 파일은 0.99 MB에서 6.74 MB 로 사이즈가 증가함을 알 수 있습니다.

이처럼 트랜잭션이 발생함에 따라 로그가 계속 쌓이면서 로그 파일의 사이즈가 계속 증가함을 알 수 있습니다. 이제 확인할 내용은 로그 백업을 하면 로그가 줄어드는지, 그리고 로그 파일의 사이즈는 어떻게 되는지 하는 것입니다.

2. 트랜잭션 로그 백업을 통한 로그 줄이기

로그 백업은 예전에 배운 데이터베이스 백업과 비슷한 방법으로 이루어 집니다. EM을 통해서 할 수도 있고 QA에서 직접 BACKUP LOG 문을 이용하여 백업 받을 수도 있습니다. 이 테스트에서는 QA를 이용하여 현재 sqlworld 데이터베이스의 로그를 백업받도록 하겠습니다.

USE Master
GO

BACKUP LOG sqlworld TO DISK = 'E:\Data\sqlworld_log.bak'

수행하는 방법은 BACKUP DATABASE 문과 비슷합니다.

만일 로그를 백업 받지는 않고 단지 현재의 로그만 지우고 싶으면 다름과 같이 TRUNCATE_ONLY 옵션을 사용하면 됩니다.

USE Master
GO

BACKUP LOG WITH TRUNCATE_ONLY

이렇게 로그를 백업 받은 후의 sqlworld 데이터베이스의 사이즈를 보니 다음 [그림 4]와 같이 변한 것을 볼 수 있습니다.


[그림4]

로그 사이즈가 3.64 MB 에서 1.84 MB로 줄어 들었습니다. 하지만 로그 파일의 사이즈는 아직도 6.74 MB로서 원래 사이즈를 그대로 유지하고 있습니다. 결국 4.9 MB의 빈 공간이 놀고(?) 있게 됩니다.

3. DBCC SHRINKDATABASE을 이용한 로그파일 사이즈 줄이기

DBCC SHRINKDATABASE 을 이용해서 수작업으로 비어있는 로그 사이즈를 없애서 로그 파일의 사이즈를 축소해 보도록 하겠습니다.

USE Master
GO

DBCC SHRINKDATABASE(Sqlworld)

결과는 다음 [그림 5]와 같이 변한것을 알 수 있습니다.


[그림5]

로그 파일의 사이즈가 [그림 4]와 비교 할 때 6.74 MB에서 2.49 MB로 줄어든 것을 알 수 있습니다. DBCC SHRINKDATABASE에 의해 줄어드는 로그 파일의 사이즈는 실제 데이터 파일의 빈 공간이 많을 수록 효과가 좋습니다. DBCC SHRINKDATABASE 또는 DBCC SHRINKFILE에 대한 내용은 이전의 데이터베이스에 대한 강좌를 참고해 주시기 바랍니다.

4. 정리

로그 파일 사이즈 문제를 가지고 질문을 하시는 경우가 상당히 많습니다. 지금까지 설명드린 내용이 도움이 되었으면 합니다. 데이터베이스 관리자는 항상 로그 파일에 대한 관심을 가지고 모니터링을 해야 합니다. 하드디스크의 여유 공간은 충분한지도 수시로 확인하셔야 합니다. 그렇지 않으면 TempDB가 꽉 찼다는 등의 오류가 발생하게 됩니다.



exec sp_helpdb dbname
backup log dbname with truncate_only
DBCC shrinkfile(dbname_log  ,5)???????????

'Programing > DB' 카테고리의 다른 글

트랜잭션 로그 줄이기 (출처:http://www.sqlworld.pe.kr)  (0) 2010.12.08
SET NOCOUNT ON  (0) 2010.12.07
Posted by 패스맨

댓글을 달아 주세요