2008년 12월 18일 목요일

DB설계할 때 주의점

DB설계에는 논리 설계와 물리 설계가 있다. 
논리설계에는 어떤 테이블, 칼럼, 키가 필요한가 고민한다. 
물리설계에서는 DB에 테이블을 작성할 때 부하의 집중정도를 생각한다거나 테이블 영역할당등을 견적을 내보곤 한다. 

I/O분산(물리설계)
MySQL의 경우, I/O분산시키는 방법에는 다음과 같은 것이 있다. 
1.  데이터베이스 디렉토리를 심볼릭링크로 한다. 
2. 로그파일위치를 지정한다. 
3.  MyISAM의 경우, 「DATA DIRECTORY」와 「INDEX DIRECTORY」키워드를 사용해서 
MYD파일과 MYI파일 위치를 변경한다. 
4. InnoDB의 경우 innodb_data_file_path로 데이터파일을 분산한다. 
5. InnoDB의 경우 innodb_log_group_home_dir로 REDO로그파일 저장위치를 변경한다. 

*심볼릭링크를 설정
MySQL에서는 데이터베이스는 디렉토리에 대응된다. Unix계열의 경우 이 디렉토리를 심볼릭링크로 해서 관리하는 게 가능하다. 이 작업을 하는데는 일단 MySQL서버를 중지시키는 게 안전하다. 
심볼릭링크의 설정방법은 보통 심볼릭링크 생성방법과 같다.  참고로 심볼릭링크로 되어있는 데이터베이스에 DROP DATABASE를 실행하면 실체가 되는 부분도 삭제되어버리므로 주의해야한다. 

윈도우에서 심볼릭링크
윈도우즈용 MySQL은 Windows98,FAT32이 주역이었던 시대에 만들어졌기 때문에 윈도우즈에서의 파일분산은 Unix계열하고는 조금 다른 방법으로 대응할 필요가 있다. 여기에서는 C:\mysql\data\test (test데이터베이스)의 내용을 D:\data\test에 배치하는 것을 전제로 설명한다. 
1. c:\mysql\data\test를 d:\data\test로 복사한다. 
2. c:\mysql\data\test.sym파일을 작성한다. 내용은 다음과 같이 실체가 있는 디렉토리 패스를 기술하는 것이다. 

   ⊙test.sym내용
  D:\data\test

이 기능은 윈도우즈에서 유효로 하기 위해서는 --symbolic-links옵션을 사용한다. 
이것으로 test데이터베이스 테이블은 모두 D:\data\test에 작성되게 된다. 
참고로 Unix계열에서 이 옵션은 다른 의미(MyISAM분산, INDEX DIRECTORY, DATA DIRECTORY유효화)가 된다. 

*로그파일 위치의 변경
MySQL에서는 로그파일의 출력위치가 지정가능하다.  이 기능으로 파일을 분산한다. 
특히 바이너리로그를 유효로 하고 있는 경우에는 그 위치를 고려하는 것이 좋다. 

*MyISAM파일의 분산
MyISAM테이블은 데이터(MYD)파일과 인덱스(MYI)파일과 테이블정의(frm)파일로 이루어져있다.  이것은 데이터베이스를 표시하는 디렉토리밑에 전부 올려져 있다. 
그러나 CREATE TABLE문에 키워드를 지정함으로써 MYD파일, MYI파일을 별도의 디렉토리에 배치하는 게 가능하다. 

   ⊙MYD파일, MYI파일을 별도의 디렉토리에 배치한다. 
  mysql> USE test;
  mysql>CREATE TABLE a ( i int) ENGINE=MYISAM DATA DIRECTORY='/disk1/data/' INDEX DIRECTORY ='/disk2/data/';

DATA DIRECTORY, INDEX DIRECTORY에는 저장위치 디렉토리를 절대패스로 저장한다. 
이 예에서는 datadir/test/a.MYD 파일은 /disk1/data/a.MYD파일에 심볼릭링크로 된다. 

이미 CREATE한 경우에는  mysqld을 일단 정지한 후 MYD파일과 MYI파일을 이동하고 심볼릭링크를 수작업으로 만든다.  ALTER TABLE에는 DATA DIRECTORY, INDEX DIRECTORY지정이 되지 않는다. 
참고로  심볼릭링크를 무효화하는 옵션 --skip-symbolic-links가 지정되어있는 경우는 이 기능은 동작하지 않으므로 주의해야한다. 

*InnoDB파일의 분산
InnoDB에서는 REDO로그파일을 쓰는 디렉토리를 저정하는 게 가능하다. 또 테이블 스페이스를 구성하는 각각의 데이터 파일을 풀 패스로 지정가능하다.  I/O분산을 하는 경우에는 이것도 고려해 두는 것이 좋을 듯 싶다. 

테이블설계(논리설계)

인덱스를 어떻게 만들까는 큰 고민이다. 
특히 InnoDB의 경우에는  primary, unique키가 없으면 행락(row lock)이 걸리지 않는다라든지 
대상이 되는 레코드이외에  스캔되는 레코드에 대해서 록이 걸리는 경우등 SQL를 사용할 때 주의가 필요하다. 
업무의 내용을 고려해서 인덱스작성을 고민해야한다. 
또  MySQL의 경우 필드수를 많이 사용할 때도 주의해야한다. 

MySQL4.1이상에서는 필드명은 utf8로 저장되어있다. 이것은 utf8이외의 캐릭터셋을 사용한 경우 필드명에 대해서 항상 문자코드변환이 이루어진다는 것을 의미한다. 5.1.12-beta의 경우에는 예를 들어 클라이언트가 latin1이고 필드의 캐릭터셋이 latin1 그리고 필드명이 알파벳문자라고 해도 이 utf8변환 로직을 사용하게 된다. 
SELECT로 취득하는 필드가 몇개 없다면 문제없지만 100개 정도되면  이 변환로직의 오버헤드는 결코 무시할 수 없다.  100개 이상의 필드를 작성해서 latin1, utf8의 경우를 비교해보면 알게된다. 

SELECT문을 실행하는 경우에는 모든 필드를 취득하는 것을 피하던지 테이블 필드를 50개이내로 하던지  모든 환경을 utf8로 하던지 해야할 것이다.