2009년 2월 26일 목요일

심볼릭링크(symbolic link)

MYD파일과 MYI파일은 심볼릭링크여도 동작한다.
파티션 용량 부족을 해결하기 위해 또는 I/O분산을 위해서 파일 본체를 별도의 디렉토리에 이동하고 데이터베이스를 나타내는 디렉토리밑에 심볼릭링크를 만드는 것이 가능하다. 

mysqld옵션(my.cnf파일)에 skip-symlink가 지정되어있으면 심볼릭링크는 사용하지 못한다. 
심볼릭링크를 사용하기 위해서는 수동으로 심볼릭링크를 만드는 방법과 CREATE TABLE문을 실행할때 특정 키워드를 지정하는 방법이 있다. 

SQL문 심볼릭링크사용예
mysql> CREATE TABLE table1 (i int) ENGINE=MYISAM DATA DIRECTORY ='/disk1/data/' INDEX DIRECTORY = '/disk2/data/';

DATA DIRECTORY에는 MYD 보존위치를 지정하고 INDEX DIRECTORY에는 MYI 보존위치를 지정한다. 

수동으로 심볼릭링크를 만드는 경우는 mysql을 정지시킨 후 작업하는 것이 안전하다. 
mysqld를 정지시킬 수 없는 경우는 SQL문으로 그 테이블을 락(lock)해놓은 후 작업한다. 

작업예
mysql> LOCK TABLES table1 WRITE;
mysql> FLUSH TABLES;

(파일 이동과 심볼릭링크 작성을 실행한다.)

mysql>UNLOCK TABLES;


2009년 2월 23일 월요일

MyISAM 파일구성

한개의 MyISAM테이블은 한개의 MYD파일과 한개의 MYI파일, 한개의 frm파일로 구성되어있다. 
파일명은 다음과 같다. 

  테이블명.확장자(MYD, MYI, frm)

이것은 데이터베이스를 나타내는 디렉토리 밑에 생성된다.  별도로 필요로 하는 파일은 없다. 

MYD파일은 데이터를 보존하고 MYI파일은 인덱스를 보존한다. 
frm은 테이블의 정의이다. 


MyISAM에 대해서

MyISAM스토리지엔진은 MySQL표준 스토리지엔진이다. 
사용자인증테이블등의 권한 테이블은 MyISAM형이어야만 한다. 

MyISAM테이블의 특징은 다음과 같다. 
  • 심플한 파일구성
  • 인덱스는 B-Tree
  • 트랜잭션은 해당없음
  • 외부키제약 없음
  • 락은 테이블락만  존재(LOCK TABLES문)
  • 압축가능
  • 심볼릭링크로 파일을 분산가능

2009년 2월 16일 월요일

MySQL5.1 스토리지엔진의 플러그인

MySQL 멀티스토리지엔진 아키텍쳐에 있어서 MySQL5.0까지는 새로운 스토리지엔진을 추가하기 위해서는 이용자가 MySQL소스를 수정해서 컴파일 할 필요가 있었다. 

그렇기 때문에 독자의 스토리지엔진을 추가 하는 것은 매우 어려운 작업이 된다. 

MySQL 5.1에서는 이 멀티스토리지엔진 아키텍쳐가 확장되어 모듈화가 진행되어지고 있다. 

MySQL 5.1에서는 새로운 스토리지를 동적으로 인스톨하거나 언인스톨하거나 하는 것이 가능하다. 

MySQL상위층(통신제어, 구문해석, 최적화등을 실행하는 부문)하고 스토리지엔진하고의 느슨한 결합(Loose coupling)이 진행되고 있다. 

MySQL 5.1에서는 새롭게 INSTALL PLUGIN하고 UNINSTALL PLUGIN라고 하는 SQL명령이 추가되었다. 
인스톨대상의 스토리지엔진은 사전에 공유 라이브러리로 해 놓을 필요가 있다. 

다음처럼 새로이 스토리지엔진을 로딩한다. 

INSTALL PLUGIN ha_example SONAME 'ha_example.so';

SONAME뒤의 값이 공유라이브러리 파일명이다.  파일은 plugin_dir로 지정한 디렉토리에 놓을 필요가 있다. 
기본 plugin_dir은 $base_dir/lib/mysql이다. 

또 다음과 같이 스토리지엔진을 언인스톨가능하다. 

UNINSTALL PLUGIN ha_example;






스토리지엔진의 또 다른 분류법

스토리지 엔진 차이에 따른 특징은 앞에서 이야기한 메모리기반/디스크기반 하고 트랜잭션 기능의 유무 이외에 다음과 같은 것이 있다. 

  • 대응하고 있는 Lock레벨
  • 대응하고 있는 인덱스의 종류
  • 참조정합성
  • 대응하고 있는 데이터형
  • 테이블정의에 관한 상한값등의 제한
예를 들면  대응하고 있는 인덱스의 종류로서는 다음과 같은 차이가 있다. 

InnoDB:BTREE
MEMORY:BTREE, HASH
MyISAM:BTREE, FULLTEXT, GIS

이처럼 엔진에 따라서 완전히 기능의 유무가 나누어져있는 것만아니라 서포트하는 범위가 다른 것도 있다. 
이 부분의 차이는 꽤 자세한 이야기가 됨으로  레퍼런스 매뉴얼을 참조하길 바란다. 

이 처럼 복수의 스토리지엔진을 준비하고 있는 MySQL이지만  MySQL에서는 모든 스토리지엔진은  Handler API라고 하는 공통 인터페이스가 있다. 

이것에 따라서 테이블마다 다른 스토리지엔진을 쓴다고 하지만  JOIN이나 UNION등의 테이블간의 처리를 실행하는 것도  가능하다. 

또 난이도가 올라가는 이야기이지만  사용자도 Handler API를 사용할 줄 만 안다면 독자의 스토리지 엔진을 MySQL에 붙이는 것도 가능하다. 
실제로 이런 구성을 이용한 OEM제품등도 존재한다. 

최근 화제가 되고 있는 OEM제품으로 Solid Information Technology사의 solidDB등이 있다. 




2009년 2월 12일 목요일

트랙잭션 기능의 유무

트랜잭션기능의 유무에 따라서 스토리지 엔진를 분류한다. 
트랜잭션기능은  많은 시스템에 있어서 없어서는 안되는 기능의 하나이지만 성능면에서 보면 매우큰 오버헤드를 낳는 기능이기도 하다.  

트랜잭션기능이 필요하지 않는 경우에는 MyISAM등의 트랜잭션이 없는 스토리지엔진을 사용하는 것으로 고속화가 기대된다. 

현재 사용하고 있는 MySQL에서 어느 스토리지 엔진이 사용가능할 까는 SQL명령어 SHOW ENGINES으로 확인할 수 있다. 

사용가능한 스토리지엔진의 확인
mysql> SHOW ENGINES;

디스크 기반 & 메모리 기반

우선 디스크에 데이터를 보존할 지  메모리에 유지시킬 지에 따라 스토리지엔진이 분류가능하다. 
일반적으로 디스크기반 스토리지엔진이더라도 데이터를 메모리에 캐쉬하는 것으로 어느정도 고속화할 수는 있다. 

그러나 역시 갱신처리등을 시작해서  코딩중 많은 부분에 있어서 디스크 I/O를 고려한 설계가 필요하다. 
그래서 처음부터 메모리에 데이터가 있는 것을 전제로한 코딩이 가능하기 때문에 메모리 기반 스토리지 엔진이 성능이 좋을 수 밖에 없다.  
그렇지만  메모리기반 스토리지 엔진은 MySQL이 크래쉬당하거나 재기동하거나하면 데이터를 잃어버리기 때문에  마스터 데이터는 별도의  장소에 보관하고  MySQL이 기동한 후에 데이터를 적절히 재취득가능하게 하는등 운용할 때  고민을 해야할 것이다. 

2009년 2월 11일 수요일

스토리지엔진의 종류, 분류

MySQL에서는 다수의 스토리지 엔진이 준비되어있지만 크게는 다음과 같이 분류할 수 있다. 

MySQL의 스토리지 엔진의 종류
                              
 디스크기준
    트랙잭션: InnoDB, BDB, Falcon
    비트랙잭션: MyISAM, MERGE, Archive, CSV
 메모리기준
     트랜잭션: NDBCluster
      비트랜잭션: MEMORY(HEAP)



2009년 2월 9일 월요일

멀티스토리지엔진의 장점((Multi Storage Engine merit)

복수의 스토리지엔진이 있어서 테이블단위로 선택할 수 있다라는게 무엇이 좋은 점인가?

보통 SQL문의 구문해석과 최적화는 CPU하고 메모리만을 사용한 처리이기 때문에  이 부분은 그다지 성능에 영향은 끼치지 않는다.  그렇지만  그 다음 스텝에서 이루어지는 데이터 검색과 저장은 디스크에 액세스하는 경우가 있어  성능에 대한 영향은 매우 크다. 
일반적으로 메모리하고 디스크는 100배이상의 액세스속도의 차가 있기때문이다. 

그것에 MySQL에서는  다루는 데이터의 특성에 맞추어서 각각 최적의 성능을 발휘할 수 있도록 하기 위한  준비로써 멀티스토리지 엔진/아키텍쳐가 제공된다. 
테이블 설계시 제3정규형으로 한 후에 성능을 고려 비정규화하거나 별도로 테이블을 잘라 만들거나 하는 경우가 있지만 MySQL에서는 특정 데이터만 별도의 테이블로 한 다음에  별도의 스토리지 엔진으로 한다거나 하는 튜닝도 가능하다. 

2009년 2월 5일 목요일

멀티 스토리지 엔진 (Multi Storage Engine)

MySQL을 다른 RDBMS하고 비교해보면 가장 큰 특징이라고 말 할 수 있는 것이 멀티스토리지 엔진 아키텍쳐이다. 

스토리지엔진은 MySQL을 구성하는 기본적인 프로그램의 한개이다. 
스토리지엔진은 데이터, 인덱스 파일에 액세스하거나 그것을 메모리에 캐쉬하면서 데이터의 검색이나 저장을 실제로 수행하는 처리를 담당하는 프로그램이다. 

이와같이 MySQL을 구성하는 다른 중요한 프로그램으로 SQL명령 문자열을 구문해석하는 SQL파서, 최적화, 실행계획을 수행하는 옵티마이저가 있다. 

예를 들어 클라이언트에서 무언가 처리를 하기 위해 SQL명령를 발행한다고 치자.
이 때 MySQL서버는  우선 최초로  그  SQL명령를 TCP/IP등의 네트워크 기능을 통해 패킷을 
수신하고  그곳에서 SQL명령 문자열을 추출한다. 
다음에 수신한 SQL명령을 구문 해석한다. 
이 부분은 SQL파서가 처리를 담당한다. 
SQL파서가 처리함으로써  그 이후에는 문자열이 아니라 보다 프로그램적인 , 처리하기 쉬운 형태로 명령어 정보가 건네지게 된다. 

옵티마이져가 SQL가 SQL문의 최적화와 인덱스등을 사용한 실행계획을 작성한다. 
이로 인해 실제로 테이블에 대한 처리를 최소화하게된다. 
최후에는 그 실행계획을 기반으로  테이블과 인덱스에 실제 액세스하게 된다. 

이 때, 테이블과 인덱스에대한  실제 액세스를  스토리지엔진이  맡고 있다. 
MySQL에서는 복수의 스토리지엔진이 준비되어있어서  이용자는 테이블을 작성할 때 「테이블 단위」로 스토리지 엔진을 선택하는 것이 가능하다.  이러한 구조를 「멀티스토리지 엔진 아키텍쳐」라고 부른다. 

이처럼 MySQL에서는 멀티스토리지 엔진 아키텍쳐가 채용된 이유로  기술적인 이야기 안에는  「스토리지 엔진」이라는 용어가 빈번하게 등장한다. 
MySQL이외의 주요한 RDBMS에서는 멀티스토리지엔진 아키텍쳐를 채용하지 않고 있기 때문에 스토리지 엔진에 대해 특별히 주목되거나 하는 것은 없지만 RDBMS의 일반적인 구조를 생각해보면  스토리지 엔진 그것은 어느 RDBMS나 존재하는 것이다. 




2009년 2월 4일 수요일

Close경우의 패킷

Close경우의 패킷
PreparedStatement의 close경우(C API에서는 mysql_stmt_close()에 해당)에는 다음과 같은 
Command Packet이 클라이언트에서 서버로 송신된다. 

PreparedStatement Close Command Packet
패킷헤더: 4바이트
명령어번호: 1바이트 , 0x19(COM_STMT_CLOSE)고정
 Statement ID: 4바이트

또  접속이 끊겼을 때에는 다음과 같은 Command Packet이 클라이언트에서 서버로 송신된다. 

Quit Command Packet
패킷헤더: 4바이트
명령어번호: 1바이트 , 0x01(COM_QUIT)고정

그 어느쪽도 서버에서 클라이언트로는 TCP응답이 되돌려질 뿐 MySQL전용의 패킷형식은 없다. 

-----------
MySQL 통신프로토콜에 관한 기술 자료로서 MySQL Internal Manual(영어)이 있다. 
다만 옛날 버전정보가 그대로 남아있거나 해서 일부 부정확한 부분도 있다. 

이 수준의 정보를 깊은 수준으로 이해하려고 한다면 소스코드를 분석할 필요가 있을 때가 온다. 
MySQL은 오픈소스이기 때문에 소스코드를 잘 보면  이런 내용들을 전부 이해할 수 있다. 







서버측커서 이용시의 패킷(packet)

서버측커서 이용시의 패킷
MySQL 5.0에서부터 서버측 커서의 기능이 지원된다.
이것을 사용하면 결과를 한번에 전부가 아니라 5레코드정도 부분단위로 단계적으로 취득하는 것이 가능하다.
배치처리등 대량의 레코드를 처리하는 경우등에 클라이언트측에서 Out of Memory가 나지 않도록 하고 싶은 경우 효과적이다.

MySQL 서버측 기능은 Prepared Statement하고 셋트로 이용한다.
당연하지만 검색용 SQL문만 이용가능하다.
패킷의 흐름은 다음과 같다.
client -> server 1. Prepare Command Packet(mysql_stmt_prepare())
server -> client 2. Prepare Packet
_Header Packet, _Placeholder Packets, _EOF Packet, _Field Packets, _EOF Packet
client -> server 3. Execute Command Packet(mysql_stmt_execute())
server -> client 4. Execute Packet
_ResultSet Header Packet, _Field Packets, _EOF Packet
client -> server 5. Fetch Command Packet(mysql_stmt_fetch())
server -> client 6. Fetch Packet
_PreparedStatement Row Data Packets, _EOF Packet
※5,6은 결과셋이 없어질 때까지 반복하는 것이 가능.

보통의 Prepared Statement하고 다른 것은 「Fetch Command Packet」이라고 하는 fetch명령용 패킷이 새로이 추가된 것과
서버에서 클라이언트에 패킷이 되돌려지는 타이밍이 바뀌었다는 것이다.

보통의 Prepared Statement에서는 Execute명령(MySQL C API에서는 mysql_stmt_execute())을 실행한 단계에서 서버에서
ResultSet Header Packet, Field Packet, EOF Packet, PreparedStatement Row Data Packet, EOF Packet 전부가 보내어진다.

한편 서버측 커서를 사용한 경우는 Execute 명령시점에서 ResultSet Header Packet, Field Packet, EOF Packet까지가 보내어진다.
나머지 PreparedStatement Row Data Packet하고 EOF Packet은 Fetch명령(C API에서 mysql_stmt_fetch())이 있을 때
보내어진다.

Fetch명령에 따라서 클라이언트에서 서버로 송출되는 Fetch Command Packet의 구성은 다음과 같다.
Fetch Command Packet
패킷헤더: 4바이트
명령어번호: 1바이트, 0x1c(COM_STMT_FETCH)고정
statement ID: 4바이트
fetch 크기: 4바이트, 16진수표현 (mysql_store_result()를 호출한 경우에는 0xff ff ff ff 가 셋팅되어 전부 반환됨)

fetch 크기를 설정하는 항목이 있어서 이 값의 레코드수 만큼 한번의 Fetch명령에 의해 서버에서 클라이언트로 반환된다.
1회의 Fetch명령에 대해서 fetch크기 만큼의 PreparedStatement Row Data Packet하고 그 뒤에 EOF Packet이 1패킷, 이 합계가 셋트로 반환된다.

EOF Packet에서는 서버의 상태정보로써 결과셋이 아직 있는지 끝났는지에 대한 정보가 설정된다.
클라이언트측에서는 이 값에 따라서 Fetch를 계속할 까 말까를 판단한다.
보통 모든 결과셋이 클라이언트에 보내어지기까지 클라이언트에서 반복해서 Fetch명령을 실행한다.





2009년 2월 3일 화요일

Prepared Statement의 패킷5

PreparedStatement Row Data Packet
결과셋 1행에 대해 PreparedStatement Row Data Packet이 1패킷 반환되어진다. 
이 구성은 보통 검색용 SQL문 실행시의 Row Data Packet하고 같다. 
다만  내용구성이 약간 다르다. 

우선 반환되는 컬럼값의 표기가  보통의 검색용 SQL문에서는 모두 문자열표현이었지만 Prepared Statement의 경우에는 다르다. 

예를 들어 INTEGER형인 경우에는 4바이트, DATETIME형이면 8바이트의 고정크기이다. 
또 null 필드라는 영역도 새롭게 추가된다. 

PreparedStatement Row Data Packet
패킷헤더: 4바이트
OK: 1바이트, 0x00고정
null필드: (field count+9)/8 바이트, 나머지수는 절사.  값은 0x00고정
컬럼값(추출하는 컬럼수만큼 반복):  문자열형은 LCS표기, 정수형은 16진수표기 
ex> 01 00 00 00  03 61 62 63 07 d6 07 0c 1e 10 12 11
     ==> 첫번째 컬럼 : 01 00 00 00 , 1 , Integer
              두번째 컬럼: 03 61 62 63,  abc, 문자열
               세번째 컬럼: 07 d6 07 0c 1e 10 12 11,  2006년  12월 30일  16시 18분 17초

       

2009년 2월 1일 일요일

Prepared Statement의 패킷4

Placeholder(「?」)에 값을 넣어, 실제로 SQL문을 실행시키는 단계(C에서는 mysql_stmt_execute()에 해당)에서는 Execute명령용 패킷이 송수신된다. 

Execute Command Packet
클라이언트에서 서버로 보내지는 패킷이다. 
placeholder의 데이터형과 설정값등의 정보가 보내지게 된다. 

 Execute Command Packet
패킷헤더: 4바이트
명령번호 : 1바이트 , execute이면 0x17(COM_STMT_EXECUTE)
 Statement ID: 4바이트
 flag(커서타입): 1바이트, 서버측 커서(STMT_ATTR_CURSOR_TYPE)기능을 사용하는 경우는 0x01, 그 이외에는 0x00
 카운터: 4바이트, 현재는 0x01 00 00 00 의 4바이트 고정
 null bit map: (7+파라미터  갯수)/8 바이트,  바인드 변수가 null을 허용할까 말까의 플래그
 send_types_to_server: 1바이트, 현재는 0x01고정
 placeholder의 데이터형: 2*n바이트,  placeholder의 갯수만큼 반복  ex> 03 00 fd 00
 placeholder의  값:  수치는 바이너리표기, 문자열, 날짜/시간형은 LCS표기
   ex>03 00 00 00 03 61 62 63  
     ==>  첫번째 placeholder : 4바이트 integer형, 값은 3   
               두번째 placeholder: 문자열 abc


명령번호는 0x17(COM_STMT_EXECUTE)이다. 

커서타입이라는 것은 MySQL5.0이후의 기능인 서버측 커서를 사용할까 아닐까하는 것을 표시하는 플래그로 사용하지 않는 경우에는 0x00 사용하는 경우에는 0x01이 된다. 

현시점의 MySQL의 서버측 커서는 읽기 전용이기 때문에 서버측 커서기능을 사용할지 않을까(0x00),  읽기 전용 서버사이트 커서기능을 사용할까(0x01) 의 두가지 선택이 가능하게 된다. 

디폴트로는 서버측 커서기능은 off이다. 
또 Prepared Statement기능을 병용사용할 필요가 있어서  보통의 SQL문하고 세트로 사용하는 것은 되지는 않는다. 

null bit map이라는 것은 각 Placeholder가 null값을 허용할까 말까를 식별하기위한 플래그이다. 
최후에 각 Placeholder의 데이터형하고 Placeholder의 설정값이 각각 반복되어 저장된다. 
데이터형은 일률 2바이트로 관리된다.  
Placeholder의 설정값은,  문자열형은 Length Coded String표기이지만 수치형은 16진수표기가 되는 등 데이터형에 따라서 다르다. 

갱신할 때에는 보통 갱신용 SQL문장의 경우와 같이 서버에서 클라이언트에 OK/Error Packet이 반환된다.  또  검색할때도 보통 검색용 SQL문과 같이 서버에서 클라이언트로 다음과 같은 구성으로 패킷이 반환된다. 

ResultSet Header Packet 1패킷
Field Packets 컬럼수만큼의 패킷
EOF Packet  1패킷
PreparedStatement Row Data Packets  레코드수만큼의 패킷
EOF Packet 1패킷

이 중에 Rows Data Packets만 레이아웃이 보통의 검색용 SQL문의 경우와 다르다.