이번 포스팅은 정말 주관적인 생각입니다.


테이블의 총 건수를 알고싶은 경우 COUNT(*)를 사용하여야 합니다.

이는 DB입장에서 메타에 총 건수를 저장하여 COUNT(*)를 호출했을 때 해당 메타 정보를 반환하지 않는 한,

언제나 Full Scan을 해야한다는 상당히 고비용의 작업이 요구됩니다.


따라서 실시간 서비스를 하는 입장에서는 부담이 큽니다.



개인적으로 생각한 대안의 방법으로는 (이 방법이 좋은지 않좋은지는 알 수 없습니다. 상황에 따라 많이 다르기도 하고요.)

물리적으로 테이블 명과 해당 테이블의 레코드 수를 저장하는 테이블을 하나 더 만들어서 그곳에 데이터를 넣는 방법을 사용하면 어떤지 생각해 봅니다.


예시로 어떤 쿼리를 보겠습니다. (문법은 무시해 주시고 의미만 파악해주시길 부탁드립니다.)

INSERT가 성공하면, 테이블 레코드를 관리하는 테이블의 레코드 기록 컬럼을 + 1

DELETE가 성공하면, 테이블 레코드를 관리하는 테이블의 레코드 기록 컬럼을 - 1  을 하는 겁니다.

이렇게 하면 COUNT(*)를 사용하지 않고도 해당 테이블의 총 데이터 건수를 확인할 수 있겠죠.

INSERT INTO dbo.T1 VALUES (1, 1);

COMMIT

IF SUCCESS

  UPDATE dbo.Tab_rowCnt SET C2 = C2 + 1 WHERE C1 = 'dbo.T1'

  COMMIT



DELETE FROM dbo.T1 WHERE C1 = 1

COMMIT

IF SUCCESS

  UPDATE dbo.Tab_rowCnt SET C2 = C2 - 1 WHERE C1 = 'dbo.T1'

  COMMIT 


SELECT C2 FROM dbo.Tab_rowCnt WHERE C1 = 'dbo.T1'


장점과 단점을 알아보겠습니다.


장점

1. 총 건수를 관리하는 테이블의 크기는 작기 때문에 증감 연산 수행 시 액세스로 인한 부하가 거의 없을 거라고 생각듭니다.

2. COUNT(*) 가 자주 수행되어야 하는 경우라면 Full Scan의 비용을 크게 줄일 수 있게 됩니다.


단점

1. 물론 INSERT, DELETE 작업의 쿼리마다 레코드수를 관리하는 테이블에 대한 쿼리를 한번 씩 더 작성해야 합니다. 이는 엄청난 관리 포인트 증가로 이어지게 될 수 있습니다.

2. COUNT(*) 쿼리는 거의 수행되지 않는 반면, 데이터 작업만 빈번하게 일어나는 서비스라면 괜한 비용낭비로 이어질 수 있습니다.

블로그 이미지

사용자 꽁담

리눅스 마스터 2급 2차 정리본을 공유하려고 합니다.

제가 직접 정리한 내용이고요, 혼자보려니 아쉬워서 공유합니다.


pdf 파일은 총 3개로 구성되어 있고, 각각의 파일들은 Section 과 주제로 정리되어 있습니다.

1. 리눅스 일반

2. 리눅스 운영관리

3. 리눅스 활용

내용은 아래 사진을 보면 대충 이렇게 구성되어 있다 느끼실 수 있구요.




책 및 유튜브로 공부하면서 개인적으로 정리한 내용이고, 만약 이게 저작권 침해에 포함된다면 바로 글 내리도록 하겠습니다.

공유는 공감+비밀댓글(메일)로 작성하신 분들에 대해서만 이뤄질 예정이며, 상업적으로 사용할 수 없다는걸 명시해주셨으면 합니다.


공부를 하신 뒤에는 기출문제를 꼭 풀어보기 바랍니다.

https://www.comcbt.com/xe/r2 링크 들어간뒤 적어도 3년치 이상 다운로드하여 유형을 파악해 보시길 바랍니다.


자료집에 없는 기출문제가 나옵니다. 따로 정리하셔서 꼭 합격하기를 바랍니다 !



시험접수는 https://www.ihd.or.kr/main.do 경로에서 하시면 됩니다.

인터넷익스플로러에서 진행해주세요.


1차는 온라이 시험으로 시험제출과 동시에 합격/불합격을 확인할 수 있고,

2차는 오프라인 시험이므로 시험장에 방문하여야 합니다.




아래는, 책없이 족보와 기출문제만 가지고 시험보고 난 점수입니다.


블로그 이미지

사용자 꽁담

DBA 란



Database Administration 해석하면 데이터베이스 관리 입니다.

데이터베이스에 관련된 모든 관리를 하는 직업군을 의미한다고 보시면 좋습니다.



DBA 가 하는일



그럼 모든 관리에는 어떤것들이 속할까요?


[개발단계] 에서는 아래와 같은 일을 합니다.

1. 기획안 분석 후 데이터베이스 관계모델 설계

2. 테이블 생성 및 프로시져 작성

3. 인덱스, 정규화, 비정규화 등의 튜닝작업


[운영단계] 에서는 아래와 같은 일을 합니다.

1. 데이터베이스 관리

2. 백업


그렇다면 여기에서 데이터베이스 관리에 한번더 궁금증이 들어갑니다. 어떤 관리지?

먼저 말하면 데이터베이스가 갑작스런 사태로 인해 죽는사태를 사전에 예방하는 역할을 말합니다.

1. 디스크관리   : 로그를 작성하던 중 디스크 풀로 인해 데이터베이스 장애가 발생할 수 있습니다.

2. CPU 사용률   : CPU 부하가 높은경우 서버가 내려갈 수 있습니다.

3. 메모리 사용률   : 메모리를 더이상 사용할 수 없는 경우 oom-killer 에 의해 프로세스가 강제 종료될 수 있습니다.

4. 데이터베이스 프로세스 상태확인    : 프로세스가 정상적인지 확인합니다.


그리고 백업. 백업은 생명이기 때문에 백업 정책을 잘 세워야 합니다.

고객의 데이터는 회사의 자산이며 해당 데이터를 잃을 경우 회사는 문을 닫아야 하니까요.



개발을 시작하고 테스트를 진행하다보면 처음 기획안에서 수정되는 경우가 많습니다.

예를 들면 컬럼이 추가되거나, 타입에 맞지않는 데이터가 들어오는 경우를 예로 들 수 있겠죠.

그렇게 되는 경우 관련된 쿼리들을 수정해야 하고, 수정된 걸 가지고 다시 모델링을 하는 경우도 생깁니다.


운영에 들어가게 되고나서는

서버 상태와 데이터베이스를 모니터링 하면서 문제가 발생할 것같은 부분을 점검시간에 수정합니다.

crontab 에 등록된 스케줄링 스크립트를 확인하여, 데이터베이스가 정상적인지 백업은 잘되었는지 등등을 확인합니다.



DBA 가 하는일의 개인적인 생각



위에처럼 DBA 는 데이터베이스를 관리하는 직군입니다.

데이터베이스를 관리하기 위해서 데이터베이스와 관련된 지식만 알면 안됩니다.


스크립트를 작성할 줄을 알아야 하며,

서버 자원에 대한 모니터링 및 튜닝도 할줄 알아야 하며,

네트워크에 대한 지식도 가지고 있어야 하며,

심지어 요즘에는 클라우드에 대한 지식도 가지고 있어야 합니다.


이와 같은 지식을 전반적으로 가지고 있었을 때, 비로소 DBA 직군에서 일하고 있다고 말할 수 있다 생각합니다.



DBA 의 미래



소규모회사같은 경우는 개발자 분들이 개발하면서 데이터베이스까지 관리하는 경우가 많지만,

회사의 규모가 점점 커질수록 데이터베이스를 전문적으로 관리하는 DBA 팀을 구성합니다.


요즘에는 "데이터베이스 자동화 툴이 너무 잘되어 있어서, 앞으로 DBA 시장이 위축될것이다" 라는 말도 있습니다.
그럼에도 불구하고 비상시를 대비하여 DBA 는 꼭 있어야 합니다.

고객의 데이터를 되살리지 못하는 경우 해당 회사는 문을 닫아야 하니까요.

블로그 이미지

사용자 꽁담

요즘은 클라우드 환경에 서버를 두고 서비스를 진행하는 방식을 많이 택합니다.

확장성과 장애 발생 시 유연하게 대처할 수 있다는 강점으로 말이죠.

이전처럼 IDC 센터에 서버를 두었던 기존방식은 클라우드라는 이름에 많이 가려진 상태입니다.


하지만 "장애 발생 시 유연하게 대처할 수 있다" 라는 말은, 말 그대로 AWS 가 아닌 고객사 서버에서 장애가 발생하는 경우이고,

이번처럼 AWS 자체에서 장애가 발생하는 경우 고객사는 AWS 장애가 복구될 때까지 손가락만 빨고 있었어야 했습니다.


클라우드에 서버를 올려서 서비스를 진행했다가 AWS 장애로 인해 서비스 장애로 이어지는 사태를 보면서 생각을 해봤습니다.

정말 AWS 클라우드에만 모든 서버를 두었을까?


데이터는 매우 중요하기 때문에 HA 방식의 구성을 택합니다. 일명 이중화 라고 하죠.

같은 데이터를 저장하고 있는 서버를 여러곳에 두어, 특정 서버에 장애가 발생하였을 경우 백업용 장비에서 서비스를 진행하는 방식으로

서비스 다운타임을 최소화 할 수 있습니다.


하지만 이번처럼 백업용 장비까지 AWS 에 있었다면?

AWS 자체가 장애 시, 모든 서버는 무용지물이 되었을테고 아무것도 손 쓸 도리가 없었겠죠.


이번 AWS 사태는 처음이었을 것이기 때문에 기업 입장에서는 해당 시나리오를 생각지 못했을 수도 있습니다.

아니라면 거의 그럴일은 없겠지만 비용문제로 인해 서버를 하나만 두었을 수도 있겠죠.


어느 고객사 같은 경우에는 서울에 원본서버, 경기도에 백업서버를 두고 서비스를 진행하고 있습니다.

물리서버이고 거리가 멀다는 점에서 이렇게 설정을 했을 겁니다.

만약 서울과 경기권 전역으로 갑자기 동시에 정전이 일어나거나 하면 어쩔 수 없겠죠?


이번 사건을 보면 결국 가상서버는 여러개를 두었지만 AWS 라고 하는 플랫폼에 종속되어 발생한 문제라고 생각합니다.

앞으로는 가상서버를 여러 클라우드에 두어, 비상시에도 대응할 수 있는 모습이 있었으면 좋겠습니다.


예를들면 아래와 같은 방식으로 말이죠.

[1차] AWS - 원본서버 [2차] Azure - 백업서버 [3차] 사내 백업서버

블로그 이미지

사용자 꽁담

안녕하세요. 모지입니다.

항상 IT 관련 포스팅만 해오다가 이렇게 제 생각을 쓰는 포스팅도 해보게 되네요.

먼 훗날에는 이글을 읽으면서 이불킥을 하게 될지도 모르지만요.ㅎ


어느덧 블로그를 시작한지도 1년이 넘어갔습니다.

길다면 길고 짧다면 짧은 시간이겠죠?


사실은 GOLDILOCKS 라고 하는 데이터베이스가 외부에 알려지지 않아서,

해당 제품을 알려보고자 하는 마음에서 시작하게 된 블로그가 살이 붙어서

GOLDILOCKS 뿐만이 아닌 ORACLE 이나 MYSQL 등의 다른 데이터베이스,

C 나 JAVA 등 여러가지를 포스팅하게 되었습니다.


소소하게 시작한 블로그가 어느덧 하루에 200명 가까운 방문자도 기록하게 되었고,

개인사로 다른회사로 이직할 때 이 블로그로 인해 점수를 받지 않았나도 생각듭니다.


최근에는 블로그에 구글 애드센스도 달렸습니다.

꾸준하게 포스팅 하다보니 이렇게 광고도 달 수 있게 되었네요.

사실 수익이 잘 나지는 않습니다. :-) 먼 훗날에는 다시 이 애드센스가 도움이 될 때도 있겠죠?


티스토리는 다음포털 블로그에 속하다보니 네이버에서 검색되어 유입되는 경우는 드뭅니다.

거의 다 google 이나 daum 에서 유입되고 있죠.

신기한 점은 IT 를 다루다 보니 그런지 몰라도 해외에서의 유입이 은근히 있습니다. 재밌는 경험입니다. ㅎㅎ

또 어느날은 갑자기 페이스북의 유입이 많아서 확인해보니 제 블로그의 하나의 포스팅이 페이스북에 링크되었더라구요.


앞으로도 꾸준히 지식을 포스팅 하여서 다른곳에서 링크되어 유입되는 경로를 많이 만들어볼까 생각하고 있습니다.

사실 요즘 너무 바쁜 하루를 보내고 있어서 포스팅 할 시간이 줄어들긴 했지만 그래도 시간이 나면 하루 한 개 포스팅을 하려고 하고있어요.

성실함과 꾸준함이 나중에 도움이 될 거라 생각하면서요.


앞으로도 저 그리고 방문자 분들과 함께 성장해 나가는 블로그를 만들어 보려고 합니다.

많은 응원 부탁드릴게요.

방문하는 모든 분들께 즐거운 하루가 되기를 !

블로그 이미지

사용자 꽁담

CHAR 와 VARCHAR



CHAR 


고정길이 문자열 타입으로 만약 타입의 크기만큼의 데이터가 들어오지 않은경우 이후의 공간을 스페이스로 채워넣습니다.

고정길이 문자열이기 때문에 헤더에는 레코드의 길이에 대한 정보가 들어있지 않습니다.



VARCHAR


가변길이 문자열 타입으로 타입의 크기만큼의 데이터가 들어오지 않더라도 이후의 공간을 스페이스로 채워넣지 않습니다.

가변길이 문자열이기 때문에 헤더에는 레코드의 길이에 대한 정보가 포함되어야 합니다.



예를들어 CHAR(5) 와 VARCHAR(5) 에 데이터 ABC 가 들어오는 경우 아래처럼 저장이 됩니다.





CHAR 와 VARCHAR 의 차이점



그렇다면 실제 쿼리에서 조회를 하게 되면 어떻게 될까요?

GOLDILOCKS 데이터베이스에서 테스트를 진행해보았습니다. ORACLE, MYSQL 등도 동일합니다.


CHAR 와 VARCHAR 타입을 가진 테이블을 생성한 뒤 데이터를 넣습니다.

CREATE TABLE Z1 (C1 CHAR(5), C2 VARCHAR(5));
INSERT INTO Z1 VALUES ('ABC', 'ABC');
COMMIT;


C1 컬럼에 대해서 비교를 해봅니다. 조건절에 'ABC ' 를 하였음에도 불구하고 데이터가 조회되는 것을 확인할 수 있습니다.

gSQL> SELECT * FROM Z1 WHERE C1 = 'ABC';

C1    C2 
----- ---
ABC   ABC

1 row selected.

gSQL> SELECT * FROM Z1 WHERE C1 = 'ABC ';

C1    C2 
----- ---
ABC   ABC

1 row selected.


C2 컬럼에 대해서 비교를 해봅니다. 조건절에 'ABC ' 를 입력하면 데이터가 조회되지 않습니다.

gSQL> SELECT * FROM Z1 WHERE C2 = 'ABC';

C1    C2 
----- ---
ABC   ABC

1 row selected.

gSQL> SELECT * FROM Z1 WHERE C2 = 'ABC ';

no rows selected.


이유는 C1 컬럼에서 빈 공간은 SPACE 로 채워지는 반면 C2 컬럼에서는 말 그대로 ABC 만 저장하기 때문입니다.

gSQL> SELECT DUMP(C1), DUMP(C2) FROM Z1;

DUMP(C1)                             DUMP(C2)                         
------------------------------------ ---------------------------------
Type=CHAR Len=5 : Str=65,66,67,32,32 Type=VARCHAR Len=3 : Str=65,66,67

1 row selected.



CHAR 와 VARCHAR 어느것을 사용해야 할까?



속도


VARCHAR 는 CHAR 타입에 대비해서 레코드의 길이가 몇이다 라는 연산을 거쳐야 합니다.

당연히 속도상에서 아주아주 미세하게 이점이 있을 수 있습니다.

그러나 이 이점은 정말 지나칠 정도의 민감함이며, VARCHAR 를 사용하여 성능저하가 느껴진다 라고 느낄일은 없다고 생각됩니다.


공간


CHAR 는 고정길이 공간 입니다. 초기의 데이터에서 더 긴 경우의 데이터로 갱신되는 경우 이미 할당해 놓은 공간을 재사용합니다.

VARCHAR 는 가변길이 공간 입니다. 초기의 데이터에서 더 긴 경우의 데이터로 갱신되는 경우 해당 공간에 쓰지 못하고 데이터 마이그레이션 현상이 나타날 수 있습니다.

그러나 벤더사별로 REORG, REBUILD 라는 분할된 블럭등을 정리하는 기능이 나오고 있습니다. 이미 나온곳도 있습니다.

그래서 VARCHAR 의 블럭분할 현상도 갱신되었다고 봅니다.



프로젝트는 진행되면서 얼마든지 변할 수 있습니다.

오히려 고정공간을 만들어 놓았다가 빈 공간에 대한 비용이 더 큰 경우가 생길 수 있으므로 저는 VARCHAR 를 추천합니다.

블로그 이미지

사용자 꽁담

Oracle, MySQL, Goldilocks 등을 활용하여 개발하시는 분들의 쿼리를 보다보면, 쿼리문에 WHERE 1 = 1 을 쓰는 모습을 종종 볼 수 있었습니다.

아무래도 소스상의 가독성 때문에 이렇게 사용하는 분들이 많이 있을텐데요.


WHERE 1 = 1 의 구문이 없는 소스의 경우와 있는 소스를 보면 가독성에 차이가 있습니다.

mozi.append(" SELECT ID, AGE "); mozi.append(" FROM MOZI "); mozi.append(" WHERE "); if ( ID != null ){ mozi.append(" ID = 91 "); } if ( AGE != null) { if ( ID != null ) { mozi.append(" AND AGE = 28"); }else{ mozi.append(" AGE = 28 "); } }

mozi.append(" SELECT ID, AGE ");
mozi.append(" FROM MOZI ");
mozi.append(" WHERE 1 = 1 ");

if ( ID != null ){
  mozi.append(" AND ID = 91 ");
}
if ( AGE != null ){
  mozi.append(" AND AGE = 28 ");
}

그렇다면, INDEX FILTER 는 탈까요?

다른 데이터베이스는 다시 확인해봐야지만 Goldilocks 에서는 Index 를 타는걸로 확인되었습니다.

gSQL> EXPLAIN PLAN
         2 SELECT ID, AGE FROM MOZI WHERE 1 = 1 AND ID = 91 AND AGE = 28;

>>>  start print plan

< Execution Plan >
==================================================================================================
|  IDX  |  NODE DESCRIPTION                                            |                    ROWS |
--------------------------------------------------------------------------------------------------
|    0  |  SELECT STATEMENT                                            |                         |
|    1  |    FILTER                                                    |                       1 |
|    2  |      INDEX ACCESS ("MOZI", "MOZI_IDX") [CLONED]              | (         1)          1 |
==================================================================================================

     1  -  READ COLUMNS : MOZI.ID, MOZI.AGE
           NODE FILTER : 1 = 1
     2  -  READ INDEX COLUMNS : ID
           READ TABLE COLUMNS : AGE
             MIN RANGE : ID = 91
             MAX RANGE : ID = 91
             PHYSICAL TABLE FILTER : AGE = 28

<<<  end print plan

이것만 놓고보면 WHERE 1 = 1 은 성능에서 부족함도 없으며, 소스에서 정말 좋은 가독성을 제공할련지도 모르겠습니다.



그렇지만 이 쿼리는 너무 위험한 데요.

만약 어떤 이유로든 ID 와 AGE 의 인자값이 NULL 이 들어왔다고 가정해봅니다.

조건절의 append 는 수행되지 않고, 이로 인해 SELECT ID, AGE FROM MOZI WHERE 1 = 1 이라는 전체 데이터를 조회하는 쿼리가 되버립니다.



그나마 SELECT 라서 다행이라지만(물론, 이로인해 전체 개인정보가 유출되었다면 심각합니다.) DELETE 라면 어떻게될까요?


DELETE FROM MOZI WHERE 1 = 1 AND ID = 91 AND AGE = 28 쿼리는

DELETE FROM MOZI WHERE 1 = 1 이라는 전체 데이터를 삭제하는 무시무시한 쿼리로 변하게 됩니다.

차라리 DELETE FROM MOZI WHERE ; 구문으로 인해 문법오류를 발생하는 편이 더 좋지않을까요?



물론 개발자 분들이 NULL 예외처리를 하겠지만, 실수와 잠재적 위험성은 언제나 도사리고 있습니다. 그것도 심각한 상황으로요.

과연 쓰는게 맞을지는 여러분들의 판단에 맡기도록 하겠습니다.

블로그 이미지

사용자 꽁담