MySQL 테이블과 인덱스 설계시 주의해야 할 13 가지

May 15, 2012


안녕하세요. 오늘은 MySQL을 사용할 때 지켜야할 사항 몇 가지 정리합니다.

나름 혼자서 정리를 해 본 것들인데, MySQL로 서비스를 준비 중이라면 한 번쯤은 고려를 해봤으면 하는 내용입니다.^^

테이블 설계 시 유의 사항

1. 반드시 Primary Key를 정의하고 최대한 작은 데이터 타입을 선정한다.

  • 로그 성 테이블에도 기본적으로 PK 생성을 원칙으로 함
  • InnoDB에서 PK는 인덱스와 밀접한 관계를 가지므로 최대한 작은 데이터 타입을 가지도록 유지

2. 테이블 Primary Key는 auto_increment를 사용한다.

  • InnoDB에서는 기본 키 순서로 데이터가 저장되므로, Random PK 저장 시 불필요한 DISK I/O가 발생 가능
  • InnoDB의 PK는 절대 갱신되지 않도록 유지
    (갱신 시 갱신된 행 이후 데이터를 하나씩 새 위치로 옮겨야 함)

3. 데이터 타입은 최대한 작게 설계한다.

  • 시간정보는 MySQL데이터 타입 date/datetime/timestamp 활용
  • IP는 INET_ATON(‘IP’), INET_NTOA(int) 함수를 활용
  • 정수 타입으로 저장 가능한 문자열 패턴은 최대한 정수 타입으로 저장

4. 테이블 내 모든 필드에 NOT NULL 속성을 추가한다.

  • NULL을 유지를 위한 추가 비용 발생
    (NULL 허용 칼럼을 인덱싱 할 때 항목마다 한 바이트 씩 더 소요)

5. Partitioning을 적절하게 고려하여 데이터를 물리적으로 구분한다.

  • 데이터 및 인덱스 파일이 커질수록 성능이 저하되므로Partitioning 유도
  • PK 존재 시 PK 내부에 반드시 Partitioning 조건이 포함되어야 함

인덱스 설계 시 유의 사항

1. 인덱스 개수를 최소화 한다.

  • 현재 인덱스로 Range Scan이 가능한지 여부를 사전에 체크
  • 인덱스도 서버 자원을 소모하는 자료구조이므로 성능에 영향을 줌

2. 인덱스 칼럼은 분포도를 고려하여 선정한다.

  • 인덱스 칼럼 데이터의 중복이 줄어들수록 인덱스는 최대의 효과를 가짐
  • 하단 쿼리 결과 값이 1에 가까울수록(0.9이상 권고) 인덱스 컬럼으로 적합함
    1
    2
    
    SELECT count(distinct INDEX_COLUMN)/count(*)
    FROM TABLE;

3. 커버링 인덱스(Covering Index)를 활용한다.

4. 스토리지 엔진 별 INDEX 특성을 정확히 인지한다.

  • InnoDB에서 데이터는 PK 순서로 저장되고, 인덱스는 PK를 Value로 가짐
  • MyISAM은 PK와 일반 인덱스의 구조는 동일하나, Prefix 압축 인덱스를 사용
    (MyISAM 엔진에서 ORDER BY 시 DESC는 가급적 지양)

5. 문자열을 인덱싱 시 Prefix 인덱스 활용한다.

  • 긴 문자열 경우 Prefix 인덱스(앞 자리 몇 글자만 인덱싱)를 적용
    1
    
    CREATE INDEX IDX01 ON TAB1(COL(4), COL(4))
  • Prifix Size는 앞 글자 분포도에 따라 적절하게 설정
    (하단 결과가 1에 가까울 수록 최적의 성능 유지, 0.9이상 권고)

    1
    2
    
    SELECT count(distinct LEFT(INDEX_COLUMN,3))/count(*)
    FROM TABLE;

6. CRC32함수 및 Trigger를 활용하여 인덱스 생성한다.

  • URL/Email같이 문자 길이기 긴 경우 유용
  • INSERT/UPDATE 발생 시 Trigger로 CRC32 함수 실행 결과 값을 인덱싱
  • CRC32 결과값을 저장할 칼럼 추가 및 인덱스 생성
    1
    2
    
    alter table user_tbl add email_crc int unsigned not null;
    create index idx01_email_crc on user_tbl (email_crc);
  • Insert Trigger 생성
    1
    2
    3
    4
    5
    6
    
    create trigger trg_user_tbl_insert
    before insert on user_tbl
    for each row
    begin
    set new.email_crc = crc32(lower(trim(new.email)));
    end$$
  • Update Trigger 생성
    1
    2
    3
    4
    5
    6
    7
    8
    
    create trigger trg_user_tbl_update
    before update on user_tbl
    for each row
    begin
    if old.email<> new.email then
    set new.email_crc = crc32(lower(trim(new.email)));
    end if;
    end$$
  • 검색 쿼리
    1
    2
    3
    4
    
    select *
    from user_tbl
    where email_crc = crc32(lower(trim('mail@domain.com')))
    and email= 'mail@domain.com'

    CRC32 결과가 중복되어도, email값을 직접 비교하는 부분에서 중복이 제거됩니다.

7. 중복 인덱스 생성 회피

  • MySQL은 동일한 인덱스를 중복 생성해도 에러를 발생하지 않음
  • Primary Key로 구성된 칼럼과 동일한 인덱스를 생성하지 않도록 주의


출처 - http://dev.kthcorp.com/2012/05/15/mysql-table-index-design-tip/






1.반드시 컴파일 하라! 10-30% 속도 향상 !

  소스를 가지고 컴파일 하세요. MySQL 메뉴얼에 따르면 10-30% 속도가 빠르다고 합니다. 
  RPM 이나 바이너리 설치를 하지 마세요 !


1-2.최신 버전을 사용하라

  최신 버전이 좋은 점은 자동 튜닝 하는 것 입니다.
  버그를 수정 하구요. 되도록 이면 최신 버전을 사용하세요 !!
  현재 3.23.49 입니다.


2. HEAP 테이블이 가장 빠르다!

  일반적으로 가장 많이 쓰이는 테이블 타입은 MyISAM 타입 입니다.
  MyISAM 타입은 무자게 빠르며, 대용량에도 강합니다. 그러나 트랜잭션은 지원되지 않습니다.
  이노디비(InnoDB) 는 트랜잭션이 지원 됩니다. 쇼핑몰에서는 반드시 사용해야 합니다 ^^

  HEAP 테이블 타입은 가장 빠르며, 단점은 메모리에 있기 때문에, MySQL에 중지 될 경우 모두 날아 갑니다. 
  검색을 하고 재검색을 다시 하는 경우, 임시 검색 테이블을 만들어 놓는 것도 좋은 방법입니다.

  HEAP 테이블 메뉴얼 !
   http://www.mysql.com/doc/H/E/HEAP.html 

  HEAP 테이블 만들기 !
  mysql>CREATE TABLE email_addresses TYPE=HEAP (
     ->email char(55) NOT NULL,
     ->name char(30) NOT NULL,
     ->PRIMARY KEY(email) );


3.mysql 서버 top 보기

  mysql 서버의 메모리 상황을 보여 주는 프로그램 입니다.
  리눅스나 유닉스의 top 기능을 mysql 에서 가능하게 한것 입니다.

  top 정보는 튜닝의 기본 이기 땜시 자주 자주 보아야 합니다. ^^
   http://public.yahoo.com/~jzawodn/mytop/ 

  PHP 소스 자료실에 파일 다운 로드 하시면 됩니다.


4.mysql_connect Vs mysql_pconnect 

  서버 메모리가 최소 2G 이상일 경우 mysql_pconnect 를 추천 함다 !
  연결을 계속 하지 않기 땜시 빠릅니다. !

  그러나 메모리가 2G 이하 일 경우는 mysql_connect 사용하세요 !


5.int,smallint,tinyint 데이터형 ! 

  int 는 굉장히 큰수 입니다. 4바이트를 차지 하구요.
  tinyint 는 몇백 까지만 됩니다. 1바이트 구요.

  쓸데 없이 int 를 사용하지 마세용 !!
  4바이트와 1바이트는 4배 차이 입니다.조그만것 1개 1개가 모여 서버 부하를 일으 킵니다.!!

  데이터 량이 얼마만큼 들어가는지 체크 하고 데이터형을 선택 하세요 ^^
  만약 쓸데없는 데이터 형이다 싶으면 alter table 로 데이터 형을 바꾸세요 !


6.인덱스의 사용 

  인덱스는 반드시 필요한 곳에만 넣으세요 !
  인덱스를 줄 경우 하드 용량을 더 차지 하기 때문에 속도를 떨어 뜨릴 수 있습니다.

  모든 칼럼에 인덱스를 주는 것은 절대 추천 하지 않습니다.
  1개의 테이블에 주키외에 2-3 개 이상의 인덱스는 주지 마세요!

  주키는 당근 인덱스 입니다. ^^

  CREATE TABLE albums (
     id     INTEGER    NOT NULL AUTO_INCREMENT PRIMARY KEY,
     title   VARCHAR(80)NOT NULL,
   
     INDEX title_idx (title)
  );

  ☞Alter Table 로 인덱스 추가 
  ALTER TABLE albums ADD INDEX title_idx (title)  

  결합 인덱스의 경우 너무 많은 인덱스를 사용할 경우 CPU 오버헤드나 하드 오버헤드를 불러 일으 킵니다.
  적당히 사용하세요 ^^

   http://www.mysql.com/doc/I/n/Indexes.html 
   http://www.mysql.com/doc/M/u/Multiple-column_indexes.html 
   http://www.mysql.com/doc/O/R/ORDER_BY_optimisation.html 


6-1. 바보 같은 인덱스의 사용 ? 

  인덱스는 %$search% 가 먹지 않습니다.
  그런디 게시판 제목(Subject) 에 인덱스 걸어 놓고 , 검색을 %$search% 이렇게 하면 될까요?
  인덱스 거나 안거나 똑같습니다. !!

  $search% 이렇게 사용하세요. 그런디.. $search% 사용하면 제목 처음 단어 밖에 검색이 안됩니다.
  그렇다면 ? 다른 검색 방법은 ?


7.UDF의 사용 

  MySQL은 스토어드 프로시져 같은 개념이 존재 하지 않습니다.
  그대신 C 언어로 만든 함수를 사용할 수 있습니다.

  조금더 빠른 쿼리를 원한다면 UDF 를 사용해보세요 !

  UDF 함수 보기 
   http://empyrean.lib.ndsu.nodak.edu/~nem/mysql/udf/ 

   http://www.mysql.com/doc/A/d/Adding_functions.html 

  스토어드 프로시져가 먼뎅?
  스토어드 프로시져는 쉽게 말해 MS-SQL 함수 입니다.
  오라클에도 아마 있을검당..^^

  그러니까 게시판에서 내용을 넘길때나 불러 올때
  mysql 쿼리가 3-4 번 정도 이루어 집니다. 또는 ms- sql 쿼리가 이루어지죵..
  3-4 번 정도 쿼리가 되면..그만큼 디비 접속이 잦아 지기 때문에..
  속도가 느려 집니다.

  많게는 10번 정도의 insert into 와 update 가 이루어집니다.

  그래서 ms - sql 자체 내에 인서트 함수 나 목록 보기 함수를 만들어 놓습니다.
  글구 1번의 ms-sql 접속만 해서 인서트 함수를 불러서 처리하는 것입니다.

  그렇기 때문에 2-3 번의 쿼리가 절약 되서 빠르다는 것이죵..ㅋㅋㅋ
  또는 10번의 쿼리 할것을 MS-SQL 스토어드 프로시져를 1번만 호출 함으로 해서 디비 접속이 절약이 되죵..ㅌㅌ


  UDF 를 꼭 사용해야 하는가?

  안해도 됩니다.만... 사용하면 좋은점 많습니다. 새로운 함수를 추가 할 수 있으므로 ^^
  MS-SQL의 스토어드 프로시져 기능 비스므리 하게 사용할 수 도 있구요...

  UDF 나 MS-SQL 스토어드 프로시져의 사용법을 익히기 보다는 캐슁을 연구하세용 ^^
  동적인 PHP 를 정적인 HTML 로 만드는 방법을요...
  또는 UDF 에서 MS-SQL 스토어드 프로시져 처럼 사용이 가능 합니다. 그 부분을 연구하세요.

  www.zdnet.co.kr 이나 www.zdnet.com 가시면 기사 파일이 1000,29920,2892.html 파일 이란것을 보게 됩니다.
  어키 구현된것일까요? zdnet 게네 들은 강좌를 원래 부터 HTML 로 만들어서 올리는 것일까용??
  HTML 로 만드는 부분도 많이 생각 해야 합니다. 강좌가 1만개 라면, 1만개의 파일이 생성 됩니다.
  zdnet 의 경우는 조회수가 10만-20만을 넘는 초대형 사이트 이기 때문에 HTML 로 만드는 것이 퍼포먼스가 좋습니다.

  UDF 배워 두면..남주지 않습니다. 


8.조인보다는 쿼리를 나누어라! 

  조인(Join)하는 것보다 쿼리를 2개로 나누는 것이 속도가 빠릅니다.
  조인을 생각 하기 이전에 쿼리를 나누는 것을 생각 하세요 ^^

  어쩔 수 없는 경우는 당근 조인 해야죠.

  글고 서브쿼리는 아직 지원 안됩니다.
  Ms-SQL이나 오라클에서 서브쿼리 보다는 서브쿼리를 하지 않는 방향의 데이터 정규화를 하세요 ^^

  조인 보다 서브쿼리가 느리다.
  서브 쿼리 보다는 조인을 사용하세요 ^^


9.full text index와 search 

  3.23.23 부터 mysql 에서는 full text index 를 지원 합니다.  자세한 사항은 아래 ! 

   http://www.mysql.com/documentation/mysql/bychapter/manual_Reference.html#Fulltext_Search 
   http://www.mysql.com/doc/F/u/Fulltext_Fine-tuning.html 


10. SELECT * FROM sometable 

  SELECT * FROM sometable 에서 * 모든을 사용하는 것은 무식한 방법 입니다.
  모든 칼럼을 불러오는 경우는 드물거든요.

  SELECT code,tadate,see FROM sometable

  사용할 것만 불러 오세요 ^^


11.데이터베이스 정규화 

  테이블을 아무렇게나 만들면 안됩니다.
  데이터베이스 정규화 원칙에 의거, 테이블을 나눌것은 나누고 만드시는 것이 좋습니다.
  제1 정규화, 제2 정규화 정도는 사용하셔야 합니다.

  게시판을 만들때 아직도 테이블 1개에 만드시나요? 
  온라인 폴 만들때 , 테이블 1개에 만드시나요?


12.REPLACE INTO문 사용하기 

  REPLACE INTO albums VALUES (6, "tood.net")   
  insert 문대신에 replace 문을 사용해보세요.
  메뉴얼 보시고 연구하세요 ^^

  주키일 경우 사용하시면 됩니다.



13. explain 사용하기 

  explain 를 사용하여 테이블의 키 값이 얼마나 잘 활용 되는지 알 수 있습니다.
  EXPLAIN SELECT, SHOW VARIABLES, SHOW STATUS, SHOW PROCESSLIST 

   http://www.mysql.com/doc/E/X/EXPLAIN.html 


17.BLOB과 TEXT는 분리하라

  BLOB과 TEXT 칼럼은 테이블을 분리 하는 것이 좋다. 다른 칼럼의 내용 보다 크기 때문이다 !

  OPTIMIZE TABLE 명령을 자주 사용해라 !
  Not null 로 지정 하는 것이 빠르다.
  varchar 보다 char 이 훨빠르다.


참고: 게시판의 특성  

  일반 게시판들 보세요. 여기 질문 게시판 만 봐도 알 수 있구요.

  읽기(select) 가 무자게 많습니다. 쓰기(insert into) 보다 30-40 배 정도 많죠.
  하룻동안 올라온 글이 30 개 라면, 하룻동안 글읽기 조회수 총 합은 최소 100 에서 900 까지 갑니다.
  물론 더 엄청날 수 있구요.

  그렇기 때문에 게시판 목록 보기와 글읽기는 HTML 파일로 만들어 놓는 것이 좋습니다.
  또는 MySQL 에서 튜닝 시에 insert 보다는 select 가 빨리 되도록 튜닝 하는 것이 좋구요 ^^


  [참고사이트]
   http://www.mysql.com/documentation/mysql/bychapter/manual_Table_types.html#SEC457 
   http://www.mysql.com/documentation/mysql/bychapter/manual_Reference.html#Fulltext_Search  

  from:
   http://www.javasun.net/board/Bread.jsp?CMD=400000&lnum=19&linenum=15&maxnum=0&keykind=null&keyword=&total=0&NCNT=1&ACMD=10&BCODE=001723 


출처 - http://leopit.com/Leophp/board/lecture_board/view.php?id=46&board_mode=mysql






MySQL 쓰면서 하지 말아야 할 것 17가지 

http://www.slideshare.net/techdude/how-to-kill-mysql-performance

작게 생각하기
- 조만간 규모가 커질거라면 MySQL ecosystem을 봐야된다.
- 그리고 캐싱 빡시게 안 하는 메이저 웹사이트는 없다.
- develooper.com의 Hansen PT랑 Ilia 튜토리얼 볼 것
- 처음부터 확장 가능하게 아키텍처 잘 쪼개놔야된다.
- 복제랑 파티셔닝 어떻게 할지 미리 계획 세워놔라.
- 파일 기반 세션 좀 쓰지마 -_-
- 그렇다고 너무 쓸데없이 크게 생각하지도 말 것
- 특히 성능하고 확장성 구분 못 하면 난감함

EXPLAIN 안 써보기
- SELECT 앞에 EXPLAIN 이라고 붙이기만 하면 되는 것을 (..)
- 실행 계획 확인
- 타입 컬럼에 index 써있는거랑 Extra 컬럼에 index 써있는거랑 "매우 큰" 차이 있음
 * 타입에 있으면 Full 인덱스 스캔 (안 좋다.)
 * Extra 컬럼에 있으면 Covering 인덱스 찾았다는 의미임 (좋다!)
- 5.0 이후부터는 index_merge 최적화도 한다.

잘못된 데이터 타입 선택
- 한 메모리 블럭 단위에 인덱스 레코드가 많이 들어갈수록 쿼리가 빨리 실행될 것이다. (중요)
아.. 정규화 좀 해 -_-... (이거 정말 충격과 공포인 듯)
- 가장 작은 데이터 타입을 써.. (진짜 BIGINT가 필요하냐고..)
- 인덱스 걸리는 필드는 정말 최소한으로 데이터 크기를 써야된다고.
- IP는 INT UNSIGNED로 저장해!! (아주 공감)
 * 이럴 때 쓰라고 INET_ATON 함수가 아예 내장되어 있음.

PHP에서 pconnect 쓰는 짓
- 아파치에서 좀비 프로세스라도 생기면 그 커넥션은 그냥 증발하는거야..
- 어차피 MySQL 접속 속도는 Oracle이나 PostgreSQL 보다 10~100배 빠르다고.

너무 과도한 DB 추상화 계층을 두는 것
- 어디 포팅 열심히 할 거 아니면 추상화 계층 쓰지마 (ADODB, MDB2, PearDB 등)
- scale out 가능한걸 쓰라고.

스토리지 엔진 이해 못 하는 것
- 단일 엔진만으로 전체 아키텍처를 결정했다면 대부분 최적이 아님
- 엔진 별 장단점을 공부할 것
- ARCHIVE : zlib으로 압축해주고 UPDATE 안 되고 로그 Bulk Insert에 유용함.
- MEMORY : 서버 재시작하면 증발. 인덱스가 HASH나 BTREE로 가능함. 임시, 요약 데이터에 사용.
 * 주간 top X 테이블 같은 것.
 * 하여튼 메모리에 박아넣고 싶은 데이터 있으면..

인덱스 레이아웃 이해 못 하는 것
- 제대로 인덱스랑 스토리지 엔진 선택하려면 공부 좀 해
- 엔진은 데이터와 인덱스 레코드를 메모리나 디스크에 레이아웃하는 걸 구현한 것
- clustered 구성은 데이터를 PK 순서에 따라 저장함.
- non-clustered 구성은 인덱스만 순서대로 저장하고 데이터는 순서 가정하지 않음.
- clustered에서는 인덱스만 타면 추가적인 조회 없이 바로 데이터 가져오는 것임.
- 그래서 clustered PK는 작은 놈으로 할 필요가 있다는거
 * 다른 인덱스는 각 레코드마다 PK를 앞에 더 붙이게 되니까.
 * PK 지정 안 하면 아무렇게나 해버림

쿼리 캐시 이해 못 하는 것
- 어플리케이션 read/write 비율은 알고 있어야지
- 쿼리 캐시 설계는 CPU 사용과 읽기 성능 간의 타협
- 쿼리 캐시 크기를 늘린다고 읽기 성능이 좋아지는게 아님. heavy read라도 마찬가지.
- 과도한 CPU 사용을 막기 위해 무효화 할 때는 캐시 항목들을 뭉텅이로 날려버림
- 한마디로 SELECT가 참조하는 테이블 데이터 하나라도 변경되면 그 테이블 캐시는 다 날라간다는 얘기임
- 수직 테이블 파티셔닝으로 처방 
 * Product와 ProductCount를 쪼갠다든지.. 
 * 자주 변하는 것과 변하지 않는 것을 쪼개는게 중요하다 이 말임.

Stored Procedure를 쓰는 것
- 무조건 쓰면 안 된다는게 아니고..
- 컴파일 할 때 무슨 일이 일어나는지 이해 못 하고 쓰면 재앙이 된다 이 말.
- 다른 RDBMS랑 다르게 connection thread에서 실행 계획이 세워짐.
- 이게 뭔 얘기냐 하면 데이터 한 번 가져오고 연결 끊으면 그냥 CPU 낭비 (7~8% 정도)하는 꼴이라는 것.
- 웬만하면 Prepared 구문과 Dynamic SQL을 써라.. 아래 경우를 제외하고
 * ETL 타입 프로시저
 * 아주아주 복잡하지만 자주 실행되지는 않는 것
 * 한 번 요청할 때마다 여러번 실행되는 간단한 것 (연결한 상태로 여러번 써야 된다니까)

인덱스 컬럼에 함수 쓰는 것
- 함수에 인덱스 컬럼 넣어 호출하면 당연히 인덱스 못 탄다
- 함수를 먼저 계산해서 상수로 만든 다음에 = 로 연결해야 인덱스 탈 수 있다.
 * 여기 실행 계획 보면 LIKE도 range type 인덱스 타는 것 보임

인덱스 빼먹거나 쓸모없는 인덱스 만들어 놓는 것
- 인덱스 분포도(selectivity)가 허접하면 안 쓴다. 
- S = d/n 
 * d = 서로 다른 값의 수 (# of distinct values)
 * n = 테이블의 전체 레코드 수
- 쓸모없는 인덱스는 INSERT/UPDATE/DELETE를 느리게 할 뿐..
- FK는 무조건 인덱스 걸어라. (물론 FK 제약 걸면 인덱스 자동으로 생긴다.)
- WHERE나 GROUP BY 표현식에서 쓰이는 컬럼은 인덱스 추가를 고려할 것
- covering index 사용을 고려할 것
- 인덱스 컬럼 순서에 유의할 것!

join 안 쓰는 짓
- 서브쿼리는 join으로 재작성해라
- 커서 제거해라
- 좋은 Mysql 성능을 내려면 기본
- 집합 기반으로 생각해야지 루프 돌리는거 생각하면 안 된다.

Deep Scan 고려하지 않는 것
- 검색엔진 크러울러가 쓸고 지나갈 수 있다.
- 이 경우 계속해서 전체 집합을 정렬한 다음 LIMIT로 가져와야 하니 무진장 느려진다.
- 어떻게든 집합을 작게 줄인 다음 거기서 LIMIT 걸어 가져올 것

InnoDB 테이블에서 WHERE 조건절 없이 SELECT COUNT(*) 하는 짓
- InnoDB 테이블에서는 조건절 없이 COUNT(*) 하는게 느리다.
- 각 레코드의 transaction isolation을 유지하는 MVCC 구현이 복잡해서 그렇다는..
- 트리거 걸어서 메모리 스토리지 엔진 쓰는 테이블에 통계를 별도로 유지하면 된다.

프로파일링이나 벤치마킹 안 하는 것
- 프로파일링 : 병목 찾아내기
- 벤치마킹 : 시간에 따른 성능 변화 추이 평가, 부하 견딜 수 있는지 테스트
- 프로파일링 할 때는 실제 데이터를 옮겨와서 할 것
- 어디가 병목이냐~ Memory? Disk I/O? CPU? Network I/O? OS?
- 느린 쿼리 로그로 남기기
 * log_slow_queries=/path/to/log
 * log_queries_not_using_indexes
- 벤치마킹 시에는 다 고정시키고 변수 하나만 바꿔가면서 해야 함. (쿼리 캐시는 끌 것.)
- 도구를 써라~~
 * EXPLAIN
 * SHOW PROFILE
 * MyTop/innotop
 * mysqlslap
 * MyBench
 * ApacheBench (ab)
 * super-smack
 * SysBench
 * JMeter/Ant
 * Slow Query Log

AUTO_INCREMENT 안 쓰는 것
- PK를 AUTO_INCREMENT로 쓰는건 무진장 최적화 되어 있음
 * 고속 병행 INSERT 가능
  * 잠금 안 걸리고 읽으면서 계속 할 수 있다는!
- 새 레코드를 근처에 놓음으로써 디스크와 페이지 단편화를 줄임
- 메모리와 디스크에 핫 스팟을 생성하고 스와핑을 줄임

ON DUPLICATE KEY UPDATE를 안 쓰는 것
- 레코드가 있으면 업데이트하고 없으면 인서트하고 이런 코드 필요없다!! 다 날려버려라!!
- 서버에 불필요하게 왔다갔다 할 필요가 없어짐
- 5-6% 정도 빠름
- 데이터 입력이 많다면 더 커질 수 있음

하지 말아야 할 것 총정리
  1. Thinking too small
  2. Not using EXPLAIN
  3. Choosing the wrong data types
  4. Using persistent connections in PHP
  5. Using a heavy DB abstraction layer
  6. Not understanding storage engines
  7. Not understanding index layouts
  8. Not understanding how the query cache works
  9. Using stored procedures improperly
  10. Operating on an indexed column with a function
  11. Having missing or useless indexes
  12. Not being a join-fu master
  13. Not accounting for deep scans
  14. Doing SELECT COUNT(*) without WHERE on an InnoDB table
  15. Not profiling or benchmarking
  16. Not using AUTO_INCREMENT
  17. Not using ON DUPLICATE KEY UPDATEK


출처 - http://xeraph.com/4286421




Posted by linuxism
,


[MySQL] BLOB, TEXT 데이터 형식 by Sigel

내가 담당하는 프로젝트(프로그램?? 암튼..) 중에 MySQL을 사용하는 서비스가 하나 있다. 여기에 갑자기 대용량의 필드를 추가할 일이 생겼다. 그래서 간만에 찾아보게 되었다.


MySQL도 대용량의 데이터를 저장할 수 있는 데이터 형식(data type)을 지원한다. BLOB과 TEXT가 그것이다. Oracle의 BLOB과 CLOB으로 볼 수 있으며, 예전에는 TEXT만 있었는데 BLOB은 언제 생겼는지 모르겠다. 워낙 오래전에 봤던 내용이라 =ㅅ=;;; 그래서 다시 보게 됐다.

BLOB과 TEXT의 차이점은..
1. MySQL의 BLOB은 "binary large object"의 약자로 binary 형태의 데이터(byte strings)를 저장하기에 적당하고, TEXT는 문자셋(Character set)에 대한 내용을 포함하기 때문에 문자형태의 데이터(character strings)를 저장하기에 적당하다.
2. BLOB은 정렬 시에 저장된 숫자값 기반으로 정렬을 수행하고, TEXT는 문자집합을 고려하여 정렬한다.
3. TEXT 필드에 인덱스(index)가 지정되어 있으면, 내용 비교 시에 마지막에 붙은 공백(trailing-space)은 무시된다. unique와 같이 인데스 비교를 하는 테이블에 "a"가 들어있다고 하자. 이 때, "a "를 넣으려고 하면 중복 오류(duplicate-key)가 발생하는 것이다. 하지만, BLOB은 그렇지 않다.

비슷한 점이라면..
문자열이 저장할 수 있는 공간보다 길어지면 문자열은 짤려서 저장되고, WARNING을 발생시킨다.


그리고 BLOB, TEXT와 비슷한 VARBINARY와 VARCHAR를 비교해 보자.
1. trailing-space의 제거 여부
BLOB과 TEXT는 문자열의 마지막에 붙은 공백(trailing-space)을 제거하지 않는다. 하지만, 5.0.3 이전 버전의 MySQL은 VARBINARY와 VARCHAR는 문자열 마지막의 공백을 제거했다. "a "를 넣으면 "a"가 되는 것이다.
2. BLOB과 TEXT는 index로 지정할 때 인덱스로 사용할 문자 길이인 index prefix length를 지정해 주어야 한다. CHAR와 VARCHAR의 경우는 옵션이다. (인덱스에 대해서는.. 7.4.3. Column Indexes)
3. BLOB과 TEXT는 DEFAULT를 설정할 수 없다.


BLOB과 TEXT는 최대 사이즈에 따라 종류가 있다.
BLOB에는 TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB이 있고, TEXT에는 TINTTEXT, TEXT, MEDIUMTEXT, LONGTEXT가 있다. BLOB과 TEXT는 2의 16제곱 바이트 가량을 담을 수 있다. (Data Type Storage Requirements의 Storage Requirements for String Types 부분 참조) LONG과 LONGVARCHAR는 MEDIUMTEXT와 매칭된다.


참고 문서
MySQL 5.0 Reference Manual 10.4.3. The BLOB and TEXT Types






Posted by linuxism
,


특정 디렉토리 하위에 대규모, 대용량의 파일을 다른 디스크로 옮기고 싶은 경우 cp 명령을 사용하면
매우 많은 시간이 소요된다. 

아래 명령을 통해 많은 시간을 단축할 수 있다. 


# cd <srcdir>
# tar cf - | ( cd <dstdir> ; tar xf - )

예제 : 


# cd /data/images
# tar cf - | ( cd /mnt/usb/images ; tar xf - )

스크립트 방식으로 작성할 경우 아래와 같은 명령 구문으로 위의 operation 내용을 단순화 
시킬 수 있다. 

# tar -C<srcdir> -cf - | tar -C <dstdir> -xf -

주의 사항 : 시스템 부하가 cp 보다 많이 걸린다. 중요한 서비스 가용 중에는 가급적 삼가하길..


출처 - http://blog.syszone.co.kr/3190


부분으로 나우어서 설명 드리면


tar
물어보고 계신 tar묶음 명령 입니다.
묶음을 만들기 위해서 실행하고 있습니다.

c
묶음파일을 만듭니다.

f
별도 지정하지 않으면 묶은 결과를 stdout즉 화면으로 출력 합니다.
그것을 별도 지정하는곳으로 출력 합니다.
여기서는 "-" 다시 stdout 으로 명시 하고 있습니다.

.
현제 디렉토리를 말하고 있습니다.

|
파이프 라인인데요.
왼쪽의 결과(stdout)를 오른쪽의 stdin 으로 넘깁니다.

cd /backup/aaa/daily.O/
이건뭐 일반적인 현제 디렉토리 변경이구요.
이렇게 하는 이유는 tar가 묶음을 풀때 타겟 디렉토리를 지정 할 수가 없고
현제 디렉토리에 풀게 되어 있습니다.
그래서 현제 디렉토리를 타겟으로 옮기는 거죠.

tar
다시 tar이군요. 이번에는 풀기 위해서 사용 하고 있습니다.

x
묶음을 풉니다.

v
좀 수다 스럽게 합니다.
진행내용을 장황하게 화면에 보여 줍니다.

f
이번에는 x와 조합이 되어서 풀려고 하는 묶음을 지정 합니다.
여기서도 "-" 이군요. 이번에는 x 와 조합되어서 stdin 이 됩니다.
stdin 은 아까 "|" 에 의해서 이전 tar의 stdout에서 오는거죠.
다시 말해는 이전 tar에서 묶은 내용 입니다.

()
명령의 묶음을 지정 합니다.
이겅의 정확한 의미는 저도 자세히는 모르겠습니다.
메뉴얼 페이지를 봐야 될것같은데... 귀차니즘이...
앞부분은 없어도 상관이 없는데 뒷부분은 없으면
tar에서 파일을 넘겨 받지 못할것같습니다.
역시 귀차니즘으로 테스트 안해봤습니다.


다시 설명을 드리면
tar로 현제디렉토리와 그 이하를
"/backup/aaa/daily.0/" 에 복사하는 내용 입니다.
cp 명령을 사용해도 되지만 원본의 파일 상태(퍼미션,날짜 등등)를
변경없이 그대로 복사할 필요가 있을때는 주로 tar을 사용 합니다.
cp도 가능은 하지만.......
둘의 차이점은 있는데.. 지금 정확히 모르겠습니다.
(자꾸 모르는것만 물어봐.... ㅠ)

암튼 도움이 되셨으면 합니다.


출처 - http://kin.naver.com/qna/detail.nhn?d1id=1&dirId=10302&docId=70984095&qb=dGFyIGNmIC0gLg==&enc=utf8&section=kin&rank=1&search_sort=0&spq=1&pid=Rt8kgF5Y7t0ssaFIM2Gssc--293400&sid=UB8bTjz7HlAAAFn6Fs8





'System > Linux' 카테고리의 다른 글

linux - 소스(source) rpm 설치  (0) 2012.08.23
linux - multitail  (0) 2012.08.23
linux - bash  (0) 2012.07.24
linux - 환경변수  (0) 2012.07.17
linux - 백그라운드 실행 & 과 nohup의 차이  (0) 2012.07.17
Posted by linuxism
,