mysql) 예약어

DB 2008. 5. 27. 00:02

mysql 4.0대에서는 sql 컬럼을 사용할 때는 문제는 없었는데, 5.0대에서는 sql 컬럼이 문제가 됨을 발견하였다. 이는 5.0대에서 새롭게 추가되었기 때문이다.

 

해결을 위해서는 두가지 방법이 있다.

1. 컬럼이름을 고치기

2. 예약어를 사용할때, TAB 키 위에 있는 ` 키 ( Single quotation )를 사용하면 된다.

 

예약어 관련해서는 아래를 참조할 것

mysql 5.0 : http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html

mysql 3점, 4점대 : http://dev.mysql.com/doc/refman/4.1/en/reserved-words.html

 

 

Posted by '김용환'
,

 


<MyISAM 튜닝>
1. 기본 설정
Key_buffer_size (기본 8Mb)
Myisam_sort_buffer_size (기본 8Mb)
Myisam_repair_threads (기본 1)
2. 이슈
key 캐시를 조정하는 것이 쿼리 성능을 높인다.
실제 데이터 row에 대한 캐시는 OS레벨에서 작동된다.
3. 성능과 연관있는 변수
- key_block_used와 key_block_unused는 얼마나 많은 쿼리캐시 공간이 사용 중인지 나타낸다.
- key_cache_block_size로 블록 사이즈를 결정한다.
- Key_buffer_size 가 높으면, 메모리가 더 할당되어 key핸들링에 사용된다. 이 값을 물리적 메모리의 25% 정도를 할당한다., 너무 크게 올리면 swapping이 일어나 성능이 저하된다.
- key_reads는 낮아야 한다.
- key_reads/key_read_requests 힛트율이 낮아야 한다.
+------------------------+--------+
| Variable_name          | Value  |
+------------------------+--------+
| Key_blocks_not_flushed | 0      |
| Key_blocks_unused      | 115964 |
| Key_blocks_used        | 16     |
| Key_read_requests      | 1125   |
| Key_reads              | 17     |
| Key_write_requests     | 65     |
| Key_writes             | 65     |
+------------------------+--------+
- Myisam_sort_buffer_size : 인덱스 생성에 사용되는 메모리의 양
- Myisam_repair_threads : 1이상으로 설정할 경우 병렬로 인덱스 생성이 가능

'DB' 카테고리의 다른 글

mysql - select 결과를 파일로 덤프하기  (0) 2008.06.24
mysql) 예약어  (0) 2008.05.27
mysql-성능튜닝 #4(innodb)  (0) 2008.05.23
mysql-성능튜닝 #2  (0) 2008.05.23
mysql- 성능 튜닝 #1  (0) 2008.05.23
Posted by '김용환'
,

mysql-성능튜닝 #4(innodb)

DB 2008. 5. 23. 07:03

 

<InnoDB 튜닝>
1. 관련 변수
- Innodb_buffer_pool_size (기본값 8Mb) : InnoDB가 사용하는 메모리 버퍼의 사이즈, OS Cache 보다 훨씬 효율적으로 메모리를 사용하여 Write 성능에 큰 영향을 미친다.
- Innodb_additional_mem_pool : Data Dictionary를 저장하기 위해서 사용되며 필요한 경우 자동으로 증가한다
- Innodb_log_file_size : InnoDB redo로그 파일 크기,  Write 성능에 영향을 미친다. 크기에 따라 InnoDB의 복구 시간이 증가한다.
- Innodb_log_files_in_group : 로그 그룹 안에 포함될 로그 파일의 수
- Innodb_log_buffer_size : 로그 버퍼 크기. 1초에 한번씩 flush 됨
- Innodb_flush_log_at_trx_commit (기본값은 1)
  : 0으로 설정하면 1초에 한번씩 디스크에 기록하고 싱크한다.
  : 1로 설정하면 commit이 발생할 때마다 디스크에 싱크한다.
  : 2로 설정하면 commit할 때마다 디스크에 기록하나 싱크는 1초에 한번만 한다.
  : 0으로 설정할 경우 여러 트랜잭션을 1초마다 한번씩 모아서 디스크에 기록함으로써 인서트 성능을 대폭 향상시키나 서버가 갑자기 다운될 경우 1초간의 트랜잭션은 상실된다.
- Innodb_thread_concurrency (기본값은 8) : InnoDB가 동시 사용가능한 최대 시스템 쓰래드 수
- foreign_key_checks/unique_checks :  InnoDB는 데이터 로드 시 기본적으로 외부키 및 키의 유일성에 대한 체크를 함께 한다. 이런 부분때문에 속도가 저하될 수 있다.
- innodb_fast_shutdown : Shutdown시 InnoDB가 내부적으로 수행하게 되는 내부 메모리 구조 정리 작업과 Insert 버퍼 정리 작업을 안한다.
- innodb_status_file: mysql 시작 옵션을  주어 InnoDB는 정기적으로 데이터의 결과를 datadir/innodb status.pid라는 파일로 저장할 수 있다.
mysql> SHOW STATUS LIKE 'innodb%'
    -> ;
+-----------------------------------+------------+
| Variable_name                     | Value      |
+-----------------------------------+------------+
| Innodb_buffer_pool_pages_data     | 32925      |
| Innodb_buffer_pool_pages_dirty    | 0          |
| Innodb_buffer_pool_pages_flushed  | 2590193    |
| Innodb_buffer_pool_pages_free     | 32609      |
| Innodb_buffer_pool_pages_latched  | 0          |
| Innodb_buffer_pool_pages_misc     | 2          |
| Innodb_buffer_pool_pages_total    | 65536      |
| Innodb_buffer_pool_read_ahead_rnd | 0          |
| Innodb_buffer_pool_read_ahead_seq | 0          |
| Innodb_buffer_pool_read_requests  | 347929888  |
| Innodb_buffer_pool_reads          | 0          |
| Innodb_buffer_pool_wait_free      | 0          |
| Innodb_buffer_pool_write_requests | 34301551   |
| Innodb_data_fsyncs                | 960103     |
| Innodb_data_pending_fsyncs        | 0          |
| Innodb_data_pending_reads         | 0          |
| Innodb_data_pending_writes        | 0          |
| Innodb_data_read                  | 0          |
| Innodb_data_reads                 | 0          |
| Innodb_data_writes                | 2275182    |
| Innodb_data_written               | 2474565120 |
| Innodb_dblwr_pages_written        | 2590020    |
| Innodb_dblwr_writes               | 160386     |
| Innodb_log_waits                  | 0          |
| Innodb_log_write_requests         | 15814690   |
| Innodb_log_writes                 | 426023     |
| Innodb_os_log_fsyncs              | 536863     |
| Innodb_os_log_pending_fsyncs      | 0          |
| Innodb_os_log_pending_writes      | 0          |
| Innodb_os_log_written             | 3444500992 |
| Innodb_page_size                  | 16384      |
| Innodb_pages_created              | 32925      |
| Innodb_pages_read                 | 0          |
| Innodb_pages_written              | 2590193    |
| Innodb_row_lock_current_waits     | 0          |
| Innodb_row_lock_time              | 0          |
| Innodb_row_lock_time_avg          | 0          |
| Innodb_row_lock_time_max          | 0          |
| Innodb_row_lock_waits             | 0          |
| Innodb_rows_deleted               | 10         |
| Innodb_rows_inserted              | 108029     |
| Innodb_rows_read                  | 51046757   |
| Innodb_rows_updated               | 3966034    |
+-----------------------------------+------------+
mysql> show engine innodb status;
....
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 1198565838; in additional pool allocated 10850304
Buffer pool size   65536
Free buffers       32609
Database pages     32925
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 0, created 32925, written 2590211
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000


2. 이슈

InnoDB의 flush를 지정할 수 있다. unix계통에서는 fsync사용한다.

'DB' 카테고리의 다른 글

mysql) 예약어  (0) 2008.05.27
mysql-성능튜닝#3(mysisam튜닝)  (0) 2008.05.23
mysql-성능튜닝 #2  (0) 2008.05.23
mysql- 성능 튜닝 #1  (0) 2008.05.23
mysql 의 wait_timeout의 의미  (0) 2008.05.23
Posted by '김용환'
,

mysql-성능튜닝 #2

DB 2008. 5. 23. 07:02


1. mysql은 동적으로 변화 가능한 옵션은 3가지로 나눌 수 있다.
- session : 조정된 값은 오직 현재 커넥션에만 영향을 미친다.
- global : 조정된 값이 전체 서버에 영향을 미친다.
- both : 값을 변화시킬 때 session/global을 반드시 명기해야 한다.


mysql> show global variables like 'query%';
+------------------------------+---------+
| Variable_name                | Value   |
+------------------------------+---------+
| query_alloc_block_size       | 8192    |
| query_cache_limit            | 1048576 |
| query_cache_min_res_unit     | 4096    |
| query_cache_size             | 0       |
| query_cache_type             | ON      |
| query_cache_wlock_invalidate | OFF     |
| query_prealloc_size          | 8192    |
+------------------------------+---------+
7 rows in set (0.00 sec)

mysql> show session variables like 'query%';
+------------------------------+---------+
| Variable_name                | Value   |
+------------------------------+---------+
| query_alloc_block_size       | 8192    |
| query_cache_limit            | 1048576 |
| query_cache_min_res_unit     | 4096    |
| query_cache_size             | 0       |
| query_cache_type             | ON      |
| query_cache_wlock_invalidate | OFF     |
| query_prealloc_size          | 8192    |
+------------------------------+---------+
7 rows in set (0.00 sec)


2.  변경된 옵션 적용하기
set global(또는 session) parameter =value
- 동작 중에 변경된 옵션은 서버 재 시작 전까지미만 적용된다.
- 영구히 변경하려면, /etc/my.cnf 파일을 수정해야 한다.
- super 권한이 있어야 바꿀 수 있다.

3. 주요 옵션 (show varialbles like '...%' 이용)
(1) table_cache (디폴트 64): 사용하는 테이블에 대한 핸들러를 캐시에 저장, opend_tables 항목이 높을 경우 table_cache를 높인다.
(2) thread_cache_size(디폴트 0) : 재 사용을 위해 보관할 쓰래드 수, thread_created가 높을 경우 증가된다. 클라이언트가 커넥션 풀을 쓰는 경우는 의미가 없다.
(3) max_connections(기본 100) : 허용 가능한 최대 동시 접속수, 쓰레드 관련 메모리 튜닝시 매우 중요, 각각의 커넥션은 최소 thread_stack의 사이즈만큼의 메모리 사용
(4) connect_timeout  : connect요청받고 몇초간 기다릴지
(5) net_buffer_length : 클라이언트에 보내는 초기 메시지의 바이트 수 조절한다.
(6) max_allowd_packet : 서버 / 클라이언트간 최대 전송 가능 패킷 크기를 설정한다., Text나 bloc컬럼이 많이 있거나, 리플리케이션을 하는 경우 최소 16M이상 잡아야 한다.
(7) back_log (디폴트 50) : connection이 대량으로 몰릴 때 큐에 대기가능한 커넥션의 갯수
(8) wait_timeout : 커넥션의 타임아웃
(9) net_retry_count : 통신이 잘못되어 실패할 때, 몇 번까지 재시도할지
(10) max_connect_error : 계속적으로 문제를 발생시키는 클라이언트를 몇번째 재시도후 block할지 지정. 한번 block되면, 서버를 재시작하거나 flush host명령을 실행하기 전까지 접속 불가 일반적인 경우.. 내부에서만 쓸 경우가 많아서 크게 잡아놓음
   나의 경우는 다음과 같이 지정
max_connections를 1000, 이때  thread_stack은 196608, thread_cache_size는 4.
connect_timeout : 5,  max_allowed_packet : 33,553,408(리플리케이션 적용) , back_log는 50
max_user_connections : 0 ,  max_connect_errors  99999999


3. 주요 환경변수 (show staus like 'thread..%' 이용)
(1) Connection관련
- Max_used_connections (720) : 피크 타임의 동시 접속 수, 튜닝의 제일 중요한 요소임
- Bytes_received (3656293909) / Bytes_sent (1293843766) : 모든 클라이언트와 전송된 바이트의 총합
- connections( 2045524 ) : 시도된 connection의 합
- Aborted_connects (40979) : 어플리케이션 또는 mysql의 커넥션 관련 옵션이 잘 못 될 수 있다.
(2) Thread 관련
-thread_created:서버 시작후, 현재까지 만들어진 총 쓰레드의 갯수
-thread_connected: 현재 열려있는 쓰레드수
-thread_cached : 재사용 가능한 동작 중이지 않은 쓰레드
-thread_running : sleeping 상태가 아닌 쓰레드 수
 [master]
| Threads_cached    | 43    |
| Threads_connected | 23    |
| Threads_created   | 66    |
| Threads_running   | 3     |
 [slave]
| Threads_cached    | 120   |
| Threads_connected | 383   |
| Threads_created   | 1681  |
| Threads_running   | 1     |
- slow_launch_threads :쓰래드 생성에 걸린 시간이 slow_launch_time 이상 걸린 쓰래드의 수. Slow_launch_time은 기본 2초이다. 0에 가까와야 좋은 것이다. 내 db는 0이군.
 *쓰레드 캐쉬의 적중률은  threads_created/connections로 계산 가능
A DB(캐슁용) : 1681/1505789 : 0.1%의 쓰레드 캐쉬의 적중률을 보여준다 (현재 thread_cache_size : 4)
B DB(어드민용) : 179348 / 2046107  : 8.7%의 쓰레드 캐쉬의 적중률을 보여준다 (현재 thread_cache_size : 128 )
=>thread_cache_size나 높여볼까나? 확실히 thread_cache_size가 높은 것이 훨씬 높다.
(3) Handler
일반적인 해석
  - handler_read_first가 높은 경우  많은 풀 인덱스 스캔이 이루어짐
  - handler_read_next가 높은 경우  풀 인덱스 스캔과 레인지 스캔이 이루어짐
  - handler_read_rnd가 높은 경우  많은 풀 테이블 스캔과 레인지 스캔이 이루어짐
  - handler_read_key가 높은 경우  인덱스를 읽는 경우가 많음
 [A DB(캐슁용)] => 별 튜닝 요소가 없다.
| Handler_commit             | 0     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 0     |
| Handler_read_key           | 0     |
| Handler_read_next          | 0     |
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 19    |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_update             | 0     |
| Handler_write              | 25    |
 [B DB(어드민용)] =>튜닝 요소가 많다.  많은 풀 테이블 스캔과 레인지 스캔이 이루어지는 것 같다.
| Handler_commit        | 199415     |
| Handler_delete        | 269322     |
| Handler_discover      | 0          |
| Handler_read_first    | 67565      |
| Handler_read_key      | 13910141   |
| Handler_read_next     | 429593667  |
| Handler_read_prev     | 2196569    |
| Handler_read_rnd      | 372568     |
| Handler_read_rnd_next | 2211096685 |
| Handler_rollback      | 1415609    |
| Handler_update        | 595584     |
| Handler_write         | 2026479    |

 

4. 성능
(1) MySQL의 느린 응답을 나타낸다. => slow_queries와 slow_launch_threads
(2) 부하가 심하다는 것을 나타낸다 =>   threads_created,  max_used_connections,  opend_tables이 큰 경우 (이 경우 table_cache를 올리자)
(3) 인덱스를 많이 읽는다. => handler_read_key가 높은 경우 
(4) 락 경쟁과 관련된 항목 =>  table_locks_waited VS table_locks_immediate , 만약 table_locks_waited가 높으면, myisam에서 innodb로 변경하는 것이 좋다.
A DB(캐슁)
| Table_locks_immediate | 20498565 |
| Table_locks_waited    | 0        |
B DB(어드민)
| Table_locks_immediate | 9500191 |
| Table_locks_waited    | 12509   |
(5) 메모리에 적용할 수 없는 큰 임시 테이블이 많이 만들어졌다 => created_tmp_disk_tables
=>  tmp_table_size를 올려서 과도한 DISK I/O가 발생하는 것을 막는다. 즉, 디스크를 안쓰고, 메모리를 쓰도록 한다.
A DB(캐슁) |Created_tmp_disk_tables | 0   (tmp_table_size | 67108864 )
B DB(어드민)| Created_tmp_disk_tables | 107  ( tmp_table_size | 33554432 )
(6)  select쿼리가 최적화 되지 못했다 => Select_xxx
=> select_full_join과 select_range_check는 많거나 다른 인덱스가 필요하다.
(6) sort_xxx 환경변수들의 값이 크다 => 쿼리에 따라 ordering 및 grouping 비용 크다.
=> sort_buffer_size가 크게 설정한다. 25%이상의 성능 향상을 기대할 수 있다. sort_buffer에 데이터를 정렬 한 후 실제 결과값을 처리하는 것은 read_rnd_buffer_size에 영향을 준다.
  

5. 최적화
(1) Table Cache 최적화
- table_cache 값을 올릴 때, mysqld가 필요로 하는 file descriptor의 수가 증가한다.
- MyISAM 엔진을 사용하는 경우 열려있는 각각의 테이블에 대해 하나의 file descriptor가 필요하게 되고, 게다가 인덱스 파일을 위해 하나의 file descriptor가 더 필요하다.
- 대부분의 운영체제에서는 프로세스당 사용할 수 있는 file descriptor의 수가 제한되는데, 이를 위해서 ulimit을 이용해서 file descript를 최대한 unlimited로 수정하는 것이 좋다.
- Opend_table 환경변수가 높을 때, 그리고 FLUSH TABLE을 자주 수행하지 않는다면 table_cache를 높이는 것이 좋다.
(2) Table Scan 최적화
- 디스크 억세스를 줄이기 위해 read_buffer가 사용된다.
- read_buffer_size는 기본 128Kb의 크기를 가지고, 높을 수록 테이블 스캔의 성능을 높여준다.
- 높여주되 지나치게 큰 값을 잡는 것은 좋지 않다. 기본적으로 테이블 스캔을 수행하는 모든 쓰래드에 할당될 수 있다.
(3) Join
- 조인되는 컬럼에 인덱스가 존재하지 않을 경우 성능이 매우 떨어진다.
- 인덱스를 추가할 수 없는 경우 join_buffer_size를 높인다.
- 두 테이블 간에 풀 조인이 일어날 경우 하나의 join_buffer가 할당되고 인덱스가 적용되지 않는 조인의 테이블 수가 늘어나는 만큼의 join_buffer가 할당된다.
(4) querty cache
select 쿼리와 그 결과를 저장한다. Query_cache_size를 클 수록 쿼리 캐시 싸이즈도 커진다. 하지만, 테이블이 바뀌면, Query cache는 모두 reset된다.
query_cache_limit을 조정함으로써 쿼리 캐시에 저장될 최대 쿼리 크기를 조절할 수 있고, Query_cache_min_res_unit(block size)를 설정하여 쿼리 캐시의 조각화를 줄일 수도 있다. 기본값은 4K이다.
Qcache_hits 와 Com_select를 비교하여 쿼리 캐시 적중률을 계산하여 성능을 최적화 할 수 있다.

'DB' 카테고리의 다른 글

mysql-성능튜닝#3(mysisam튜닝)  (0) 2008.05.23
mysql-성능튜닝 #4(innodb)  (0) 2008.05.23
mysql- 성능 튜닝 #1  (0) 2008.05.23
mysql 의 wait_timeout의 의미  (0) 2008.05.23
mysql&gt; show variables  (0) 2008.05.23
Posted by '김용환'
,

mysql- 성능 튜닝 #1

DB 2008. 5. 23. 07:01

0. mysql 성능 모니터링
(1) 툴
[리눅스]
- vmstat, iostat, mpstat
[mysql]
- SHOW STATUS 커맨드를 통해 현재 서버 상태를 파악
- Cricket, SNMP 또는 자체 제작 스크립트를 사용
- MySQL Administrator
[기타툴]
mytop
innotop (http://www.xaprb.com/blog/2006/07/02/innotopmysql-innodb-monitor)


(2) mysql
show full processlist
show status (mysqladmin extended-status, MySQL Administrator이용)
ex) mysqladmin –i 1 extended-status      1초마다 mysql 의 전체 status 확인 가능

급박한 경우는 kill을 사용하면 된다. kill

시간이 오래걸리는 프로세는 perl코드를 이용하여 조절이 가능하다.
$result = mysql_query("SHOW FULL PROCESSLIST");
while ($row=mysql_fetch_array($result)) {
    $process_id=$row["Id"];
    if ($row["Time"] > 200 ) {
        $sql="KILL $process_id";
        mysql_query($sql);
    }
}

 

 


1. staus 항목 분석
(1) com_xxx 항목은 서버 시작 이후 xxx 관련 명령이 얼마나 수행됐는지를 나타냄
ex) com_select는 총 수행된 select 쿼리 수
Com_begin, Com_commit, Com_rollback, Com_insert, Com_update, Com_select, Com_delete
(2) questions는 서버로 전송된 총 쿼리 수를 나타냄

'DB' 카테고리의 다른 글

mysql-성능튜닝 #4(innodb)  (0) 2008.05.23
mysql-성능튜닝 #2  (0) 2008.05.23
mysql 의 wait_timeout의 의미  (0) 2008.05.23
mysql&gt; show variables  (0) 2008.05.23
mysql 기본 설정 보기  (2) 2008.05.23
Posted by '김용환'
,

 

 

어느 날부터 java가  DB와의 연결이 timeout이 되어 버려 원인을 찾던중, 뜻밖의 좋은 문서를 발견하였다. wait_timeout이 정말 짧아서 나는 것인지, 아니면, 원인이 다른데에 있는지 원인을 찾던 중 좋은 문서를 발견하였다..

 

 

출처 :

http://www.linuxchannel.net/docs/mysql-timeout.txt

 

 

[MySQL] time out(wait_timeout) 계산과 설정

- 작성자 : 김칠봉 <san2(at)linuxchannel.net>
- 작성일 : 2003-08-11(보완, 그래프 추가)
           2003-08-04
- 내  용 : life time 계산에 의한 wait_timeout 설정
- 수  준 : 초중급 이상
- 키워드 : MySQL, wait_timeout, interactive_timeout, connect_timeout,
           max_connections, Aborted_clients, Connections,
           Max_used_connections, Slow_queries, Questions, Uptime

*주1)
이 문서에 대한 최신 내용은 아래 URL에서 확인할 수 있습니다.

http://www.linuxchannel.net/docs/mysql-timeout.txt

*주2)
이 문서에서 사용한 life time, EXP, CUR, PAS, POL, DEF, LPT ... 와 같은
용어는 필자가 자의적으로 붙인 가칭용어로써 공식적인 용어가 아닙니다.

---------------------------------------------------------
목차

0. 배경

1. MySQL의 time out
  1-1. connect_timeout
  1-2. interactive_timeout
  1-3. wait_timeout

2. 연결 취소율(POC)과 connection life time
  2-1. 연결 취소율(POC)
  2-2. connection life time

3. 임계 life time
  3-1. 현재 최대(최악) 예상 임계 life time (EXP)
  3-2. 현재 평균 임계 life time (CUR)
  3-3. 지난 과거 최대 임계 life time (PAS)
  3-4. 지난 과거 유추 최대 임계 life time (POL)

4. 임계 life time(LPT) 계산(예제)

5. wait_timeout 계산 및 보정

6. 결과 확인

7. 후기
---------------------------------------------------------


0. 배경

아주 바쁜 MySQL 서버에서는 간혹 'Too many connections' 이라는 에러를 만날
수 있을 겁니다.

대부분 이 에러를 해결하기 위해서,

  - max_connections
  - wait_timeout

이 두개의 파라메터를 튜닝하면서 설정하는 것이 일반적입니다.

그런데, MySQL 매뉴얼에는 이 에러에 대한 자세한 설명이 빠져 있습니다.

예를들어, 실제 Max_used_connections 이 한계 max_connections 에 도달하지 않았는데도
불구하고 이런 에러를 만나면 상당히 난처합니다.

이런 경우는 대부분  max_connections 값을 올리고, wait_timeout 값을 줄여서 튜닝
하곤 하지만 역시 정확한 튜닝이 어렵습니다.

실제로 좀더 정확하게 튜닝하기 위해서는,

  - 시스템 전체 상황(실제 어느 정도로 바쁜지에 대한 상대적 수치),
  - 초당 connections 수,
  - 커넥션당 평균 쿼리 요청수,
  - 커넥션당 생성된 평균 쓰레드 수
  - 초당 평균 전송량
  - DISK에 생성된 임시 테이블 생성 비율
  - Slow_queries
  - 한계 도달 N 초 계산
  - 커넥션 life time

이런 값들을 계산 및 고려하여,

  - max_connections
  - wait_timeout
  - back_log
  - thread_cache_size
  - key_buffer_size
  - record_buffer (read_buffer_size)
  - record_rnd_buffer
  - sort_buffer_size
  - 기타 메모리 설정

이런 파라메터에 설정을 해줘야 합니다.

실제 MySQL 서버의 파라메터 설정은,

  1) 사용가능한 최대 전체 데이터베이스 크기와 각 테이블 평균 크기 계산
  2) MySQL 이 사용하는 시스템 물리적 메모리 크기
  3) 1)에 의한 shared 메모리와 쓰레드 메모리 할당 및 계산
  4) 2)과 3)에 의한 최대 동시 접속 가능한 max_connections 계산
  5) time out 설정
  6) 그 외 설정
  7) 시스템을 운영하면서 지난 통계 데이터에 의한 설정값 다시 튜닝

이와 같은 순서로 튜닝해 나가야 합니다.

2)번과 3)번 같은 경우는

  MySQL 이 사용할 물리적 메모리 총합 =
  (
      key_buffer_size +
      (read_buffer_size + sort_buffer_size) * max_connections
  )

이와 같은 공식을 사용합니다.
전자의 key_buffer_size 는 모든 쓰레드들이 항상 공유해서 사용하는 shared
메모리이고, 그 밑의 두개는 각 쓰레드마다 사용하는 not shared 메모리입니다.

간략하게 정리하면 다음과 같습니다.

  MySQL caches(all threads shared)
  (
      - key_buffer_size	        : 8MB < INDEX key
      - table_cache             : 64 < number of open tables for all threads
      - thread_cache_size       : 0 < number of keep in a cache for reuse
  )

  MySQL buffers(not shared)
  (
      - join_buffer_size        : 1MB < FULL-JOIN
      - myisam_sort_buffer_size : 8MB < REPAIR, ALTER, LOAD
      - record_buffer           : 2MB < sequential scan allocates
      - record_rnd_buffer       : 2MB < ORDER BY(avoid disk)
      - sort_buffer             : 2MB < ORDER BY, GROUP BY
      - tmp_table_size          : 32MB < advanced GROUP BY(avoid disk)
  )

  MySQL memory size
  (
      - INDEX(key)              : 8MB < key_buffer_size (shared)
      - JOIN                    : 1MB < join_buffer_size (not shared)
      - RECORD(read)            : 2MB < record_buffer (not shared)
                                : 2MB < record_rnd_buffer (not shared)
      - SORT                    : 8MB < myisam_sort_buffer_size (not shared)
                                : 2MB < sort_buffer (not shared)
      - TABLE(temporary)        : 32MB< tmp_table_size(not shared)
  )

  MySQL timeout
  (
      - connect_timeout         : 5 > bad handshake timeout
      - interactive_timeout     : 28800 > interactive to re-interactive timeout
      - wait_timeout            : 28000 > none active to re-active timeout
  )

  MySQL connections
  (
       - max_connections        : 100 < 'to many connections' error
       - max_user_connections   : 0(no limit) < user limit
  )


이 글은 메모리 설정에 관한 내용은 상당히 방대하므로 여기에서는 제외하고,
MySQL 의 time out 계산에 관한 내용입니다.

  이 글의 전제 조건
  (
      - MySQL 서버가 상당히 바빠서 time out 설정이 필요하다.
      - 서버의 바쁜 정도와 데이터베이스 크기에서 계산한
        max_connections 설정값이 현재 MySQL 서버의 한계점이다.
        (초과시 서버 증설이 필요함)
      - 연결 취소율(Aborted_clients*100/Connections)이 높은 경우
        (튜닝 기준 0.1% 또는 0.5% 이상)
  )

  time out 설정 목적
  (
      - 제한된 자원(메모리)의 효율적 이용
      - MySQL 성능 극대 (한계점에 극대, 한계점을 초과하지 않음)
      - 원할한 커넥션 처리
      - 절대적으로 불필요한 커넥션을 강제로 close(불필요한 커넥션 반환)
      - 기타
  )


1. MySQL의 time out

MySQL 서버(정확히 `mysqld')의 time out 설정은 크게 3가지가 있습니다.

  mysqld time out
  (
      - connect_timeout (bad handshake timeout)
      - interactive_timeout (interactive 모드에서 connection time out)
      - wait_timeout (none interactive 모드에서 connection time out)
  )

connect_timeout, interactive_timeout 은 튜닝과 좀 거리가 멀고,
실제로 바쁜 서버라면, 반드시 wait_timeout 을 따로 튜닝하여 설정해줘야 합니다.
(실제 이 글의 내용임)


1-1. connect_timeout

이 설정은 mysqld 와 mysql client 가 연결(connection)을 맺기 위해서
mysqld 가 연결 패킷을 기다리는 최대 시간입니다.

즉 TCP 연결을 맺는 과정(3-way handshake)에서, connect_timeout 동안에도
연결 패킷이 들어오지 않으면 연결이 실패(취소가 아님)되고,
bad handshake 로 응답합니다.

  *참고)
  (
      - 연결 실패 : 연결 과정중에서 fail 되는 경우 (Aborted_connects)
      - 연결 취소 : 연결이 된 상태에서 강제로 close 된 경우 (Aborted_clients)
  )

바꾸어 말하면 mysqld 와 mysql client 가 TCP 연결을 맺는 최대 시간으로
이 시간보다 큰 경우는 모두 Aborted_connects 에 해당됩니다.
(단위는 초)

  연결 실패율(POF) =
  (
      Aborted_connects * 100 / Connections
  )

  연결이 실패되는 경우
  (
      - 연결 패킷에 올바른 연결 정보가 없는 경우
      - 특정 user 가 권한이 없는 데이터베이스에 접근할 경우
      - mysqld 접근 password 가 틀린 경우
      - connect_timeout 보다 긴 연결 과정
  )

연결 실패율(POF)이 높은 경우는, 대부분 권한이 없는 데이터베이스 연결이나,
틀린 password 를 사용할 경우가 많습니다.

기본값은 대부분 5(초)로 설정되어 있으며, 따로 튜닝할 필요는 없습니다.
mysqld 의 --warnings 옵션 사용과 xxx.err 파일에 기록됩니다.


1-2. interactive_timeout

interactive 모드에서 time out 을 말합니다.
interactive 모드는 'mysql>' 과 같은 프롬프트 있는 콘솔이나 터미널 모드를
말합니다.

mysqld 와 mysql client 가 연결을 맺은 다음, 다음 쿼리까지 기다리는
최대 시간을 의미합니다.

설정된 interactive_timeout 까지도 아무런 요청(쿼리)이 없으면 연결은
취소되고, 그 이후에 다시 요청이 들어오면 연결은 자동으로 맺어집니다.

interactive_timeout 안에 다시 요청이 들어오면 wait time은 0으로 초기화
됩니다(CLIENT_INTERACTIVE).

  ERROR 2006: MySQL server has gone away
  No connection. Trying to reconnect...
  Connection id:    12002
  Current database: xxx

이와 같은 연결 취소는 Aborted_clients 에 누계되고, wait_timeout 의
결과도 함께 포함됩니다

기본 값은 28800(8시간) 초로 설정되어 있는데 상당히 관대한(?) 설정입니다.
약 1시간(3600) 정도로 설정하는 것을 권장합니다.


1-3. wait_timeout

이 설정은 제일 중요한 파라메터 항목입니다.

interactive 모드가 아닌 경우에 해당되며,
mysqld 와 mysql client 가 연결을 맺은 후, 다음 쿼리까지 기다리는
최대 시간을 의미합니다.

즉 대부분 PHP 나 C, PERL, python 등등의 API 를 이용한 client 프로그램
모드를 말합니다.

interactive_timeout 과 마찬가지로 wait_timeout 까지 아무런 요청(쿼리)이
없으면 연결은 취소되고 그 결과는 Aborted_clients 에 누계됩니다.

wait_timeout 안에 다시 요청이 들어오면 wait time 은 0 으로 초기화 됩니다.
(SESSION.WAIT_TIMEOUT)

  연결 취소율(POC) =
  (
      Aborted_clients * 100 / Connections
  )

  연결이 취소되는 경우(강제 종료됨)
  (
      - 종료(exit) 되기전 mysql_close() 가 없는 경우
      - wait_timeout 이나 interactive_timeout 시간까지 아무런 요청(쿼리)
        이 없는 경우
  )

기본 값은 interactive_timeout 과 마찬가지로 28800(8시간) 초로 설정되어
있는데, 역시 너무 관대한(?) 설정이라고 할 수 있습니다.

앞에서 연결 취소율(POC)을 계산해 보면, MySQL 서버가 어느 정도 비율로 강제
종료하는지 알 수 있습니다.

예를 들어 POC 가 1 % 이라면, 100 개의 커넥션당 하나 정도는 mysql_close()
없이 강제 종료(exit)되고 있다는 의미입니다.

이 값이 0 %에 가까울수록 좋습니다. 이 의미는 클라이언트 프로그램에서
모두 정상적으로 종료했다는 의미입니다.


2. 연결 취소율(POC)과 connection life time

2-1. 연결 취소율(POC)

연결 취소율 값이 지나치게 높으면, wait_timeout 설정이 너무 짧거나,
대부분 client 프로그램이 exit(종료)를 정상적으로 하지 않은 경우이므로 반드시
튜닝이 필요합니다.

특히 서버가 매우 바쁜 경우는, 이 wait_timeout 시간을 짧게 설정하여 불필요한
커넥션을 모두 제거해 줘야합니다(메모리 한계 문제).

  wait_timeout 튜닝이 필요한 경우
  (
      - 보통 POC(연결 취소율)가 1 % 이상인 경우
      - 아주 바쁜 서버에서는 튜닝전 0.01 % 이상인 경우
      - 기타 튜닝 기준에 따라 다름
  )

주의할 점은,

client 프로그램(예: PHP)을 수정하지 않는 상태에서, wait_timeout 을 튜닝하면
튜닝전에 비해서 POC 가 더 올라가야 정상입니다. 이 의미는 비정상적인 커넥션을
반환하는 비율이므로, 정상적인 서비스하에서 이 값이 올라가야 함을 이미합니다.

  warning
  (
      이하 다루는 'life time' 이나 '임계 life time' 등의 내용은 반드시
      wait_timeout 튜닝이 필요한 경우에 해당됩니다.

      만약, wait_timeout 튜닝이 필요하지 않다면 이하 내용을 필요하지 않습니다.
  )


그럼 이제 wait_timeout 값을 계산해 봅시다.

이 값을 계산하기 위해서 mysqld 로그 파일을 분석해야 하는데,
불행히도 시간 기록이 1 초 간격으로 기록되어 있어서 접속이나 close 또는
각 쿼리 시간 통계를 구하기 어렵습니다.
(표본을 하루 단위로 축출하여 계산할 경우, 좀더 정확한 자료가 됨)

따라서, 현재 MySQL 서버의 STATUS 통계 자료를 이용하는 것도 하나의 방법입니다.

  통계를 얻는 방법
  (
      mysql> tee /path/to/mysql.status.txt
      mysql> SHOW STATUS;

      or
      shell> mysqladmin [OPTIONS] extended-status > mysql.status.txt
  )

  주요 MySQL STATUS
  (
      Aborted_clients
      Connections
      Max_used_connections
      Slow_queries
      Questions
      Uptime
      ...
  )

직접적인 평균 wait_timeout 값을 구할 수 없기 때문에,
각 커넥션을 일렬로 늘어놓은 상태의 평균적인 커넥션 life time 값을
구해야 합니다.


2-2. connection life time

'life time' 은 하나의 커넥션이 연결된 후 완전히 close 될 때까지 시간을 말하며,
필자가 자의적으로 붙인 용어입니다.

즉, 여기에서의 life time 은 하나의 커넥션이 살아있는 동안의 시간을 말하며,
이 시간에는 쿼리 실행, connection idle, wait timeout, interactive timeout 등등이
모두 포함되어 있는 time을 말합니다.

  조건
  (
      connection idle ==> wait time out
      interval of connection ==> 0
  )


  가정
  (
      +----------------------------+------------------->+--------->
      |connection                  |               close|connection
      |<-- queries execute time -->|<-- wait timeout -->|
      |<------------- connection life time ------------>|
  )

  life time (하나의 커넥션당 평균)
  (
      = 쿼리 실행 시간(long query 포함)
      += { wait timeout | interactive timeout }
  )


  life time =
  (
      connection
      [ wait time out ]
      [ += 1'th query execute time ]
      [ += wait time out]
      [ += 2'th query execute time ]
      [ += wait time out]
      [ ... ]
      [ += wait time out]
      [ += n'th query execute time ]
      [ += wait time out]
      close
  )


  커넥션 관련 통계
  (
      cps = Connecions / Uptime    ; // 초당 커넥션 수
      spc = Uptime / Connections   ; // 커넥션 주기(초)
      cpq = Question / Connections ; // 커넥션당 요청 쿼리 수
  )

실제 life time 은 mysqld 로그 파일을 분석해봐야 하는데,
이것 역시 상당히 까다롭습니다(exit 시간 기록이 없기 때문).

따라서, 여기에서는 '실제 life time'이 아닌 가상의 '임계 life time'
를 구해서 wait time out 설정에 중요한 자료로 활용하고자 하는 것이
이 문서의 본 내용입니다.


3. 임계 life time

모든 커넥션이 close 되지 않는다는 가정하에서, 즉 모든 커넥션이
한번 접속후 계속적으로 살아있다는 가설을 내리고,
한계 도달 N sec 를 구해서 이에 대한 평균값(AVG)을 구해보면
이 평균값이 커넥션당 '평균 임계 life time'이 됩니다.

바꾸어 말하면,
모든 커넥션들을 꼬리에 꼬리를 무는 가상의 평균적인 일직선으로 만들어
놓고, 한계 도달 N sec 를 구하는 방법입니다
(커넥션과 커넥션 간격을 0으로 봄).

  문제가 되는 경우'
  (
      <FONT FACE='굴림체'>
      동시 접속 connection 수(Y)
      |
      + Max connection ------+------+------
      |                     '|      |
      |                    ' |      |
      |                   '  |      |
      |                 .    |      |
      |               .      |      |
      |             .        |      |
      | . . . . . '          |      |
      |                      |      |
      +----------------------+------+-------> X sec
                             N sec
      </FONT>
      * 시간이 지남에 따라 급격한 기울기(오목한 분포)
  )

  잘 튜닝된 경우
  (
      <FONT FACE='굴림체'>
      동시 접속 connection 수(Y)
      |
      + Max connection ------+------+------
      |                       . ' ' |
      |                     .       |
      |                   '         |
      |                 '           |
      |               .             |
      |             .               |
      | . . . . . '                 |
      |                             |
      +----------------------+------+-------> X sec
                                    N sec
      </FONT>
      * 시간이 지남에 따라 완만한 기울기(볼록한 분포)
  )


  가정
  (
      <FONT FACE='굴림체'>
      동시 접속 connection 수(Y)
      |
      + Max connection -------------+------
      |              |           . '|
      |              |       . '    |
      |              |   . '        |
      |              + '            |
      |          . ' |              |
      |      . '     |              |
      |  . '         |              |
      |              |              |
      +--------------+--------------+-------> X sec
                   (N+1)/2          N sec
      </FONT>
      * 커넥션 간격을 0으로 봄(직선적 기울기)
  )


  한계 도달 N sec 계산법
  (
      1 sec : 1 * cps
      2 sec : 2 * cps
      3 sec : 3 * cps
      ...
      N sec : N * cps => max_connections or Max_used_connections
  )
  or
  (
      N sec : max_connections or Max_used_connections / cps
  )


  최대(최악 상태) 한계 도달 life times 분포와 그 평균값(AVG) 계산법
  (
      1 sec : 1 * cps'th connection : N sec (life time)
      2 sec : 2 * cps'th connection : N - 1 sec
      3 sec : 3 * cps'th connection : N - 2 sec
      ...
      N sec : N * cps'th connection(max) : N - (N -1) sec

      AVG   : (N + 1) / 2 sec (life time) ; // 임계 life time
  )

모든 커넥션이 각각(평균) 이 '임계 life time'와 같거나 더 클 경우
결국 N sec 에 도달해서 full connection 이 된다는 의미입니다.
그 반대로,
커넥션 평균 life time 이 임계 life time 보다 작으면 N sec 이후에서
full connection 이 된다는 결론이 나옵니다.

이것은 mysqld 가 최악의 상태를 말하며, 아주 바쁜 MySQL 서버이거나
아주 바쁜 시간대(rush hour)에 충분히 이런 상황이 될 수 있다는 것을
반증합니다.

이 '임계 life time' 을 구해서 wait_timeout 설정하는데 중요한 자료로
활용하는 것이 본 글의 목적이며, 이 '임계 life time'을 다른 변수값들과
서로 보정하여 최종 wait_timeout 으로 설정하는 내용입니다.


  현재 최대(최악) 예상 임계 life time 계산(EXP)
  (
      N sec = max_connections / cps
            = max_connections * spc
            = max_connections * Uptime / Connections

      임계 life time(EXP)
            = (N + 1) / 2
  )


  현재 평균 임계 life time 계산(CUR)
  (
      N sec = Max_used_connections / cps
            = Max_used_connections * spc
            = Max_used_connections * Uptime / Connections

      임계 life time(CUR)
            = (N + 1) / 2
  )

  지난 과거 최대 임계 life time 계산(PAS)
  (
      N sec = Max_used_connections / maximum of cps
            = Max_used_connections * minimum of spc

      임계 life time(PAS)
            = (N + 1) / 2
  )

  지난 과거 유추 최대 임계 life time 계산(POL)
  (
      N sec = max_connections / maximum of cps
            = max_connections * minimum of spc

      임계 life time(POL)
            = (N + 1) / 2
  )


3-1. 현재 최대(최악) 예상 임계 life time(EXP)

이 값은 MySQL 서버가 시작후 현재까지의 초당 평균 커넥션 수('이하 'cps')
를 기준으로 계산할 때, full connection 인 max_connections 에 도달할 때의
평균 임계 life time 입니다.

즉 모든 커넥션은 각각 절대로 이 EXP 보다 크면 안된다는 의미가 됩니다.
(한계점이므로)

실제로 (wait_timeout > EXP) 경우는 wait_timeout 효과를 기대하기 어렵습니다.

  예를 들어
  (
      wait_timeout = 120
      EXP          =  63
  )

이와 같은 경우가 많은데, 이것을 분석(해석)해 보면,
모든 커넥션의 평균 임계 life time 이 64 초인데 굳이 120 초까지 기다려서
close 하는 경우가 거의 없다는 의미가 됩니다. 물론 평균적인 계산할 때의
얘기입니다.

따라서 최소한 wait_timeout 은 EXP 와 같거나 이 값보다 작게 설정해주는 것이
효과가 있습니다.(크면 별 효과를 기대하기 어려움)


3-2. 현재 평균 임계 life time (CUR)

이 값은 현재까지 최대 동시 접속 커넥션(Max_used_connections)에 도달할 때의
평균 임계 life time 입니다.

즉 life time 이 현재 추세로, 평균적으로 진행할 때의 임계 life time 입니다.

EXP 보다 항상 작거나 같습니다. 서로 같은 경우는 지난 과거에 벌써
full connection 까지 도달했다는 의미가 됩니다.

이 값은 단지 평균적인 현재 추세를 알아보는데 유용합니다.

그런데,

EXP 와 CUR 모두 현재 평균적인 추세에 대한 life time 입니다.
모든 프로그램이 그렇듯이 평균적인 작동원리는 설정은 상당히 위험합니다.
즉 최악의 상태까지 고려해서 프로그램에 임해야 한다는 것입니다.

따라서, EXP와 CUR 값보다 더 작은 임계 life time 을 구해야 하는데,
이것은 지난 과거에 가장 바빴던 cps 로 계산한 POL 해야 합니다.


3-3. 지난 과거 최대 임계 life time (PAS)

지난 과거중에서 최대 cps 값을 선택하여 계산할 때의 임계 life time 입니다.
이 값은 다른 임계 life time 보다 항상 작습니다.

과거중에서 최대 cps 구하는 방법이 조금 까로운데 이것은 매 시간대마다 또는
rush hour 에 체크하여 그 통계의 결과치를 구해야 합니다.

만약 최대 cps 를 구하기 어려우면 현재 평균 cps * (1.5 ~ 2.0) 정도로 계산하면
됩니다.

이 PAS 값은 wait_timeout 값을 구하는데 결정적인 자료로 쓰이며,
CUR 의 보정값이라고 생각하면 됩니다.


3-4. 지난 과거 유추 최대 임계 life time (POL)

EXP 가 현재 평균 cps 값으로 계산한 임계 life time 에 반해서, POL 은 PAS 와
같이 과거중 최대 cps 값으로 계산한 임계 life time 입니다.

즉,
EXP 는 평균적 cps 에 의해서 각 커넥션을 일직선으로 늘어 놓는데 반해서,
POL 은 최대 cps 에 의해서 각 커넥션을 일직선으로 늘어 놓은 상태에서 계산한
life tiem 값입니다.

이 값도 PAS 와 같이 wait_timeout 값을 구하는데 결정적인 자료로 쓰이며,
EXP 의 보정값이라고 생각하면 됩니다.


4. 최종 임계 life time(LPT) 계산(예제)

실제 예를 들어 보겠습니다.

  ex1
  (
      max_connections      = 100
      Max_used_connections =  13
      AVG of cps           = 0.1
      MAX of cps           = 0.3
  ); // 매우 바쁘지 않지만 과거 어느 순간에 극대로 바빴던 경우

  ex2
  (
      max_connections      = 100
      Max_used_connections =  92
      AVG of cps           = 0.8
      MAX of cps           = 1.1
  ); // 비교적 바쁜 서버로써 거의 한계점에 도달하고 있는 경우

  ex3
  (
      max_connections      = 100
      Max_used_connections = 100
      AVG of cps           = 2.4
      MAX of cps           = 2.7
  ); // 아주 바쁜 서버로 과거에 이미 한계점에 초과한 경우

<FONT FACE='굴림체'>
+------+------+------+---------+-----------+-------+-------+
| 구분 |  EXP |  POL |         |  CUR (C%) |  PAS  | (DEF) |
|------+------+------+---------+-----------+-------+-------|
| ex1  |  201 |  167 |         |  66 (33%) |   22  |   44  |
|------+------+------+---------+-----------+-------+-------|
| ex2  |   63 |   46 |         |  58 (92%) |   42  |   16  |
|------+------+------+---------+-----------+-------+-------|
| ex3  |   21 |   19 |         |  21(100%) |   19  |    2  |
+------+------+------+---------+-----------+-------+-------+
</FONT>
* C%  : (CUR * 100 / EXP) ; // 평균 cps 에 대한 임계 도달 사용율
* DEF : CUR - PAS ; // 편차

서버가 바쁠수록 EXP 나 CUR 값이 점점 작아지고, C% 값은 점점 커집니다.

각각 max_connections이 서버의 한계라는 설정에서 EXP 나 CUR 값이 10 보다
작으면 서버의 증설이 필요하다는 것을 의미합니다.
(slow query 10 sec 에 기준을 둔다면)

여기에서 중요한 임계 life time 은 PAS 값인데,
이 PAS 값은 제일 바쁜 상태가 계속된다는 가정이므로 다른 값보다 항상
제일 작습니다.

실제 위의 예를 보면,
ex1이 ex2 보다 평균적으로 더 바쁘지 않지만 PAS 값이 더 작습니다.
이 의미는 과거의 어느 순간에 ex2 보다 더 바빴다는 증거이고 앞으로
그럴 가능성이 있다는 의미입니다.

DEF 값이 크다는 의미는 평균과 최대치의 life time 의 차가 크다는 의미로
서버가 바쁠때와 그렇지 않을때의 차가 크다는 의미입니다.

또한 PAS 값이 10 보다 작으면 서버 증설 필요성이 상당히 높다는 의미가
됩니다. (slow query 10 sec 에 기준을 둔다면)

EXP, POL, CUR, PAS 중에서 튜닝할 임계 life time 값을 선택해야 하는데,
POL 이나 PAS 값 중에서 하나를 선택하면 됩니다.

POL 값을 선택할 경우는 매우 관대한 정책(설정)이 될 것이고, PAS 값을
선택하면 매우 제한적인 설정이 됩니다.

주의할 점은 선택한 임계 life time 이 10 보다 작으면 서버가 아주 바쁜
상태에 목표를 두고 튜닝해야 하므로 주의해야 합니다.

여기에서는 편의상 PAS 값을 선택하겠습니다.

그런데 ex1 같은 경우는 DEF 편차가 상당히 큰데, ex1 비교적 그리 바쁘지
않으므로 그 다음으로 작은 CUR 값을 선택하는 것이 좋습니다.

만약 서버가 전체적으로 비교적 바쁘다고 생각하면 제일 작은 PAS 값을
선택하면 됩니다.

<FONT FACE='굴림체'>
+------+----------------------------------+
| 구분 |  최종 임계 life time (LPT)       |
|------+----------------------------------|
| ex1  |            66                    |
|------+----------------------------------|
| ex2  |            42                    | 
|------+----------------------------------|
| ex3  |            19                    |
+------+----------------------------------+
</FONT>


5. wait_timeout 계산 및 보정

이제 life time 이 결정되었으니 wait_timeout 값을 설정해 봅시다.

앞서 얘기했듯이 life time 은 각 커넥션을 평균적으로 일직선상에
놓았을 경우, 한계 도달 시간을 의미합니다.

즉 각 커넥션은 평균적으로 이 life time 값을 넘어서면 안된다는 의미
입니다. (max_connections 값이 이미 정해진 한계이기 때문에)

LPT 값이 19 이라면(ex3의 경우),

  cpq = 8(예)
  (
      Questions / Connections
  ); // 커넥션당 평균 쿼리 요청수

  LPT =
  (
      (connection)
      (
          [ = wait time out]
          [ += 1'th query execute time ]
      )
      (
          [ += wait time out]
          [ += 2'th query execute time ]
      )
      (
          [ ... ]
      )
      (
          [ += wait time out]
          [ += n'th query execute time ] ; // n => cpq
          [ += wait time out]
      )
      (close)
  ) < 19

이런 조건식이 나옵니다.

그리고
하나의 쿼리가 실행한 시간과 그 다음 쿼리까지의 시간을 평균적으로
계산하면 다음과 같습니다.
  
  2.4 sec = 19 / 8 = LPT / cpq

보통 하나의 쿼리가 실행하는 시간은 상당히 짧은 0.001 ~ 2.0 sec 정도
되는 것이 보통입니다.(물론 예외도 있음)

그러면 대충 wait time out 값을 계산 또는 짐착할 수 있습니다.
즉 평균적으로 2.4 초 보다 항상 작다는 결론이 나옵니다.

그러나

이 값을 곧바로 wait_timeout 값으로 설정하면 상당히 위험합니다.
이 값은 어디까지나 평균적인 수치일 뿐 편차에 대한 고려가 전혀 없습니다.

예를 들어, 각 커넥션마다 쿼리가 하나이면 상관은 없지만,
다음과 같은 경우가 상당히 많기 때문입니다.

  life time
  (
      connection
      (
          = wait time out                 ; // 0.1 sec
          = 1'th query execute time       ; // 0.4 sec
      )
      (실제 쿼리에 상관없는 작업 시간 = 3.1 sec)
      (
          += wait time out                ; // 3.1 sec > 2.4 sec
          += 2'th query execute time      ; // 0.2 sec
      )
      close
  ) < 19 ; // 예제

따라서 앞에서 계산한 2.4 sec 는 실제로 wait_timeout 에 적용하기에는
매우 적절하지 않습니다.

결론적으로

하나의 커넥션이 최소한 하나 이상의 쿼리가 있는 경우가 거의 대부분이므로
이 점을 고려서 계산하면 다름과 같은 최종적인 계산식이 나옵니다.

  wait_timeout
  (
      = LPT - (LPT / cpq)
      = LPT - (LPT * Connections / Questions)
  )
  * 단) LPT > 10
  * 단) cpq > 1
  * 단) wait_timeout > 10 (한계값, slow query 고려)


<FONT FACE='굴림체'>
+------+-------+----------+--------------------+---------+
| 구분 |  LPT  |  cpq(예) |    wait_timeout    |   AVG   |
|------+-------+----------+--------------------+---------|
| ex1  |   66  |     5    |         53         |    59   |
|------+-------+----------+--------------------+---------|
| ex2  |   42  |     7    |         36         |    39   |
|------+-------+----------+--------------------+---------|
| ex3  |   19  |     9    |         17         |    18   |
+------+-------+----------+--------------------+---------+
</FONT>

이 wait_timeout 은 상당히 제한적인 정책입니다.
좀더 관대한 설정을 원한다면 LPT 값을 wait_timeout 값으로 설정하거나
LPT와 계산한 wait_timeout 과 평균값(AVG)을 최종 wait_timeout 값으로
설정하면 됩니다.


6. 결과 확인

이제 최종적으로 wait_timeout 값이 정해졌므로 이 값을 서버에 적용해
봅니다.

  적용 예
  (
      shell> safe_mysqld ... -O wait_timeout=17 &

      or

      [mysqld]
      ...
      set-variable    = wait_timeout=17
  )


튜닝전에 비해서 연결 취소율(POC)이 더 올라가야 정상입니다.
이 의미는 비정상적인 커넥션을 반환하는 비율이므로, 성공적인
튜닝이라고 할 수 있습니다.



7. 후기

헙... 어디에서 쇠(?) 타는 냄새가 난다했더니....
CPU 팬이 안도네요(설마 설마 했더니)....T.T
그것도 AMD CPU ....
제가 냄새에 민감해서 천만다행..



EOF
 

'DB' 카테고리의 다른 글

mysql-성능튜닝 #2  (0) 2008.05.23
mysql- 성능 튜닝 #1  (0) 2008.05.23
mysql&gt; show variables  (0) 2008.05.23
mysql 기본 설정 보기  (2) 2008.05.23
mysql 5.0의 사용자 관리 페이지  (0) 2008.04.25
Posted by '김용환'
,

mysql&gt; show variables

DB 2008. 5. 23. 00:56

 

mysql> show variables
    -> ;
+---------------------------------+----------------------------------------+
| Variable_name                   | Value                                  |
+---------------------------------+----------------------------------------+
| back_log                        | 50                                     |
| basedir                         | /usr/local/mysql/                      |
| binlog_cache_size               | 32768                                  |
| bulk_insert_buffer_size         | 8388608                                |
| character_set_client            | euckr                                  |
| character_set_connection        | euckr                                  |
| character_set_database          | euckr                                  |
| character_set_results           | euckr                                  |
| character_set_server            | euckr                                  |
| character_set_system            | utf8                                   |
| character_sets_dir              | /usr/local/mysql/share/mysql/charsets/ |
| collation_connection            | euckr_korean_ci                        |
| collation_database              | euckr_korean_ci                        |
| collation_server                | euckr_korean_ci                        |
| concurrent_insert               | ON                                     |
| connect_timeout                 | 5                                      |
| datadir                         | /usr/local/mysql/var/                  |
| date_format                     | %Y-%m-%d                               |
| datetime_format                 | %Y-%m-%d %H:%i:%s                      |
| default_week_format             | 0                                      |
| delay_key_write                 | ON                                     |
| delayed_insert_limit            | 100                                    |
| delayed_insert_timeout          | 300                                    |
| delayed_queue_size              | 1000                                   |
| expire_logs_days                | 0                                      |
| flush                           | OFF                                    |
| flush_time                      | 0                                      |
| ft_boolean_syntax               | + -><()~*:""&|                         |
| ft_max_word_len                 | 84                                     |
| ft_min_word_len                 | 4                                      |
| ft_query_expansion_limit        | 20                                     |
| ft_stopword_file                | (built-in)                             |
| group_concat_max_len            | 1024                                   |
| have_archive                    | NO                                     |
| have_bdb                        | NO                                     |
| have_compress                   | YES                                    |
| have_crypt                      | YES                                    |
| have_csv                        | NO                                     |
| have_example_engine             | NO                                     |
| have_geometry                   | YES                                    |
| have_innodb                     | YES                                    |
| have_isam                       | NO                                     |
| have_ndbcluster                 | NO                                     |
| have_openssl                    | NO                                     |
| have_query_cache                | YES                                    |
| have_raid                       | NO                                     |
| have_rtree_keys                 | YES                                    |
| have_symlink                    | YES                                    |
| init_connect                    |                                        |
| init_file                       |                                        |
| init_slave                      |                                        |
| innodb_additional_mem_pool_size | 1048576                                |
| innodb_autoextend_increment     | 8                                      |
| innodb_buffer_pool_awe_mem_mb   | 0                                      |
| innodb_buffer_pool_size         | 8388608                                |
| innodb_data_file_path           | ibdata1:10M:autoextend                 |
| innodb_data_home_dir            |                                        |
| innodb_fast_shutdown            | ON                                     |
| innodb_file_io_threads          | 4                                      |
| innodb_file_per_table           | OFF                                    |
| innodb_flush_log_at_trx_commit  | 1                                      |
| innodb_flush_method             |                                        |
| innodb_force_recovery           | 0                                      |
| innodb_lock_wait_timeout        | 50                                     |
| innodb_locks_unsafe_for_binlog  | OFF                                    |
| innodb_log_arch_dir             |                                        |
| innodb_log_archive              | OFF                                    |
| innodb_log_buffer_size          | 1048576                                |
| innodb_log_file_size            | 5242880                                |
| innodb_log_files_in_group       | 2                                      |
| innodb_log_group_home_dir       | ./                                     |
| innodb_max_dirty_pages_pct      | 90                                     |
| innodb_max_purge_lag            | 0                                      |
| innodb_mirrored_log_groups      | 1                                      |
| innodb_open_files               | 300                                    |
| innodb_table_locks              | ON                                     |
| innodb_thread_concurrency       | 8                                      |
| interactive_timeout             | 28800                                  |
| join_buffer_size                | 131072                                 |
| key_buffer_size                 | 402653184                              |
| key_cache_age_threshold         | 300                                    |
| key_cache_block_size            | 1024                                   |
| key_cache_division_limit        | 100                                    |
| language                        | /usr/local/mysql/share/mysql/english/  |
| large_files_support             | ON                                     |
| license                         | GPL                                    |
| local_infile                    | ON                                     |
| locked_in_memory                | OFF                                    |
| log                             | OFF                                    |
| log_bin                         | ON                                     |
| log_error                       |                                        |
| log_slave_updates               | OFF                                    |
| log_slow_queries                | ON                                     |
| log_update                      | OFF                                    |
| log_warnings                    | 1                                      |
| long_query_time                 | 5                                      |
| low_priority_updates            | OFF                                    |
| lower_case_file_system          | OFF                                    |
| lower_case_table_names          | 0                                      |
| max_allowed_packet              | 10484736                               |
| max_binlog_cache_size           | 4294967295                             |
| max_binlog_size                 | 1073741824                             |
| max_connect_errors              | 99999999                               |
| max_connections                 | 1000                                   |
| max_delayed_threads             | 20                                     |
| max_error_count                 | 64                                     |
| max_heap_table_size             | 16777216                               |
| max_insert_delayed_threads      | 20                                     |
| max_join_size                   | 4294967295                             |
| max_length_for_sort_data        | 1024                                   |
| max_relay_log_size              | 0                                      |
| max_seeks_for_key               | 4294967295                             |
| max_sort_length                 | 1024                                   |
| max_tmp_tables                  | 32                                     |
| max_user_connections            | 0                                      |
| max_write_lock_count            | 4294967295                             |
| myisam_data_pointer_size        | 4                                      |
| myisam_max_extra_sort_file_size | 2147483648                             |
| myisam_max_sort_file_size       | 2147483647                             |
| myisam_recover_options          | OFF                                    |
| myisam_repair_threads           | 1                                      |
| myisam_sort_buffer_size         | 67108864                               |
| net_buffer_length               | 16384                                  |
| net_read_timeout                | 30                                     |
| net_retry_count                 | 10                                     |
| net_write_timeout               | 60                                     |
| new                             | OFF                                    |
| old_passwords                   | OFF                                    |
| open_files_limit                | 16000                                  |
| pid_file                        | /usr/local/mysql/var/sky279.pid        |
| port                            | 3308                                   |
| preload_buffer_size             | 32768                                  |
| protocol_version                | 10                                     |
| query_alloc_block_size          | 8192                                   |
| query_cache_limit               | 1048576                                |
| query_cache_min_res_unit        | 4096                                   |
| query_cache_size                | 0                                      |
| query_cache_type                | ON                                     |
| query_cache_wlock_invalidate    | OFF                                    |
| query_prealloc_size             | 8192                                   |
| range_alloc_block_size          | 2048                                   |
| read_buffer_size                | 520192                                 |
| read_only                       | OFF                                    |
| read_rnd_buffer_size            | 262144                                 |
| relay_log_purge                 | ON                                     |
| rpl_recovery_rank               | 0                                      |
| secure_auth                     | OFF                                    |
| server_id                       | 2                                      |
| skip_external_locking           | ON                                     |
| skip_networking                 | OFF                                    |
| skip_show_database              | OFF                                    |
| slave_net_timeout               | 3600                                   |
| slow_launch_time                | 2                                      |
| socket                          | /tmp/mysql.sock                        |
| sort_buffer_size                | 524280                                 |
| sql_mode                        |                                        |
| storage_engine                  | MyISAM                                 |
| sync_binlog                     | 0                                      |
| sync_replication                | 0                                      |
| sync_replication_slave_id       | 0                                      |
| sync_replication_timeout        | 0                                      |
| sync_frm                        | ON                                     |
| system_time_zone                | KST                                    |
| table_cache                     | 512                                    |
| table_type                      | MyISAM                                 |
| thread_cache_size               | 4                                      |
| thread_stack                    | 196608                                 |
| time_format                     | %H:%i:%s                               |
| time_zone                       | SYSTEM                                 |
| tmp_table_size                  | 33554432                               |
| tmpdir                          |                                        |
| transaction_alloc_block_size    | 8192                                   |
| transaction_prealloc_size       | 4096                                   |
| tx_isolation                    | REPEATABLE-READ                        |
| version                         | 4.1.10-log                             |
| version_comment                 | Source distribution                    |
| version_compile_machine         | i686                                   |
| version_compile_os              | pc-linux-gnu                           |
| wait_timeout                    | 28800                                  |
+---------------------------------+----------------------------------------+

 

 

 

 

/etc/my.cnf 파일에 wait_timeout을 1800000 값을 주고 다시 뛰우니. 다음과 같이 값을 얻어올 수 있었다.


mysql> select @@global.wait_timeout
    -> ;
+-----------------------+
| @@global.wait_timeout |
+-----------------------+
|               1800000 |
+-----------------------+
1 row in set (0.00 sec)

mysql> select @@session.wait_timeout
    -> ;
+------------------------+
| @@session.wait_timeout |
+------------------------+
|                  28800 |
+------------------------+
1 row in set (0.00 sec)

 

 

 

'DB' 카테고리의 다른 글

mysql- 성능 튜닝 #1  (0) 2008.05.23
mysql 의 wait_timeout의 의미  (0) 2008.05.23
mysql 기본 설정 보기  (2) 2008.05.23
mysql 5.0의 사용자 관리 페이지  (0) 2008.04.25
mysql에서 row를 세로로 보기  (0) 2008.04.25
Posted by '김용환'
,

mysql 기본 설정 보기

DB 2008. 5. 23. 00:52

mysql 기본 디폴트 설정 보기.

 

 

/usr/local/mysql/bin/mysql --no-defaults --help

 

/etc/my.cnf /usr/local/mysql/var/my.cnf ~/.my.cnf
The following groups are read: mysql client
The following options may be given as the first argument:
--print-defaults        Print the program argument list and exit
--no-defaults           Don't read default options from any options file
--defaults-file=#       Only read default options from the given file #
--defaults-extra-file=# Read this file after the global files are read

Variables (--variable-name=value)
and boolean options {FALSE|TRUE}  Value (after reading options)
--------------------------------- -----------------------------
auto-rehash                       TRUE
character-sets-dir                (No default value)
default-character-set             euckr
compress                          FALSE
database                          (No default value)
delimiter                         ;
vertical                          FALSE
force                             FALSE
named-commands                    FALSE
local-infile                      FALSE
no-beep                           FALSE
host                              (No default value)
html                              FALSE
xml                               FALSE
line-numbers                      TRUE
unbuffered                        FALSE
column-names                      TRUE
sigint-ignore                     FALSE
port                              3306
prompt                            mysql>
quick                             FALSE
raw                               FALSE
reconnect                         TRUE
socket                            (No default value)
table                             FALSE
debug-info                        FALSE
user                              (No default value)
safe-updates                      FALSE
i-am-a-dummy                      FALSE
connect_timeout                   0
max_allowed_packet                16777216
net_buffer_length                 16384
select_limit                      1000
max_join_size                     1000000
secure-auth                       FALSE

 

 

 

'DB' 카테고리의 다른 글

mysql 의 wait_timeout의 의미  (0) 2008.05.23
mysql&gt; show variables  (0) 2008.05.23
mysql 5.0의 사용자 관리 페이지  (0) 2008.04.25
mysql에서 row를 세로로 보기  (0) 2008.04.25
Toad 단축키.  (0) 2008.04.19
Posted by '김용환'
,

이 내용만큼 좋은 정보를 발견하지 못했다 추천!!

 

 

http://dev.mysql.com/doc/refman/5.0/en

 

 

 

5.5.1. MySQL Usernames and Passwords

A MySQL account is defined in terms of a username and the client host or hosts from which the user can connect to the server. The account also has a password. There are several distinctions between the way usernames and passwords are used by MySQL and the way they are used by your operating system:

  • Usernames, as used by MySQL for authentication purposes, have nothing to do with usernames (login names) as used by Windows or Unix. On Unix, most MySQL clients by default try to log in using the current Unix username as the MySQL username, but that is for convenience only. The default can be overridden easily, because client programs allow any username to be specified with a -u or --user option. Because this means that anyone can attempt to connect to the server using any username, you cannot make a database secure in any way unless all MySQL accounts have passwords. Anyone who specifies a username for an account that has no password is able to connect successfully to the server.
  • MySQL usernames can be up to 16 characters long. This limit is hard-coded in the MySQL servers and clients, and trying to circumvent it by modifying the definitions of the tables in the mysql database does not work.

Note

You should never alter any of the tables in the mysql database in any manner whatsoever except by means of the procedure prescribed by MySQL AB that is described in Section 4.4.9, “mysql_upgrade — Check Tables for MySQL Upgrade”. Attempting to redefine MySQL's system tables in any other fashion results in undefined (and unsupported!) behavior.

Operating system usernames are completely unrelated to MySQL usernames and may even be of a different maximum length. For example, Unix usernames typically are limited to eight characters.

  • MySQL passwords have nothing to do with passwords for logging in to your operating system. There is no necessary connection between the password you use to log in to a Windows or Unix machine and the password you use to access the MySQL server on that machine.
  • MySQL encrypts passwords using its own algorithm. This encryption is different from that used during the Unix login process. MySQL password encryption is the same as that implemented by the PASSWORD() SQL function. Unix password encryption is the same as that implemented by the ENCRYPT() SQL function. See the descriptions of the PASSWORD() and ENCRYPT() functions in Section 11.10.2, “Encryption and Compression Functions”. From version 4.1 on, MySQL employs a stronger authentication method that has better password protection during the connection process than in earlier versions. It is secure even if TCP/IP packets are sniffed or the mysql database is captured. (In earlier versions, even though passwords are stored in encrypted form in the user table, knowledge of the encrypted password value could be used to connect to the MySQL server.)

When you install MySQL, the grant tables are populated with an initial set of accounts. These accounts have names and access privileges that are described in Section 2.4.16.3, “Securing the Initial MySQL Accounts”, which also discusses how to assign passwords to them. Thereafter, you normally set up, modify, and remove MySQL accounts using statements such as GRANT and REVOKE. See Section 12.5.1, “Account Management Statements”.

When you connect to a MySQL server with a command-line client, you should specify the username and password for the account that you want to use:

shell> mysql --user=monty --password=guess db_name

If you prefer short options, the command looks like this:

shell> mysql -u monty -pguess db_name

There must be no space between the -p option and the following password value. See Section 5.4.4, “Connecting to the MySQL Server”.

The preceding commands include the password value on the command line, which can be a security risk. See Section 5.5.6, “Keeping Your Password Secure”. To avoid this problem, specify the --password or -p option without any following password value:

shell> mysql --user=monty --password db_name

shell> mysql -u monty -p db_name

When the password option has no password value, the client program prints a prompt and waits for you to enter the password. (In these examples, db_name is not interpreted as a password because it is separated from the preceding password option by a space.)

On some systems, the library routine that MySQL uses to prompt for a password automatically limits the password to eight characters. That is a problem with the system library, not with MySQL. Internally, MySQL doesn't have any limit for the length of the password. To work around the problem, change your MySQL password to a value that is eight or fewer characters long, or put your password in an option file.


 

 

5.5.2. Adding New User Accounts to MySQL

You can create MySQL accounts in two ways:

  • By using statements intended for creating accounts, such as CREATE USER or GRANT
  • By manipulating the MySQL grant tables directly with statements such as INSERT, UPDATE, or DELETE

The preferred method is to use account-creation statements because they are more concise and less error-prone. CREATE USER and GRANT are described in Section 12.5.1.1, “CREATE USER Syntax”, and Section 12.5.1.3, “GRANT Syntax”.

Another option for creating accounts is to use one of several available third-party programs that offer capabilities for MySQL account administration. phpMyAdmin is one such program.

The following examples show how to use the mysql client program to set up new users. These examples assume that privileges are set up according to the defaults described in Section 2.4.16.3, “Securing the Initial MySQL Accounts”. This means that to make changes, you must connect to the MySQL server as the MySQL root user, and the root account must have the INSERT privilege for the mysql database and the RELOAD administrative privilege.

As noted in the examples where appropriate, some of the statements will fail if you have the server's SQL mode has been set to enable certain restrictions. In particular, strict mode (STRICT_TRANS_TABLES, STRICT_ALL_TABLES) and NO_AUTO_CREATE_USER will prevent the server from accepting some of the statements. Workarounds are indicated for these cases. For more information about SQL modes and their effect on grant table manipulation, see Section 5.1.6, “SQL Modes”, and Section 12.5.1.3, “GRANT Syntax”.

First, use the mysql program to connect to the server as the MySQL root user:

shell> mysql --user=root mysql

If you have assigned a password to the root account, you'll also need to supply a --password or -p option for this mysql command and also for those later in this section.

After connecting to the server as root, you can add new accounts. The following statements use GRANT to set up four new accounts:

mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost'

    ->     IDENTIFIED BY 'some_pass' WITH GRANT OPTION;

mysql> GRANT ALL PRIVILEGES ON *.* TO 'monty'@'%'

    ->     IDENTIFIED BY 'some_pass' WITH GRANT OPTION;

mysql> GRANT RELOAD,PROCESS ON *.* TO 'admin'@'localhost';

mysql> GRANT USAGE ON *.* TO 'dummy'@'localhost';

The accounts created by these GRANT statements have the following properties:

  • Two of the accounts have a username of monty and a password of some_pass. Both accounts are superuser accounts with full privileges to do anything. One account ('monty'@'localhost') can be used only when connecting from the local host. The other ('monty'@'%') can be used to connect from any other host. Note that it is necessary to have both accounts for monty to be able to connect from anywhere as monty. Without the localhost account, the anonymous-user account for localhost that is created by mysql_install_db would take precedence when monty connects from the local host. As a result, monty would be treated as an anonymous user. The reason for this is that the anonymous-user account has a more specific Host column value than the 'monty'@'%' account and thus comes earlier in the user table sort order. (user table sorting is discussed in Section 5.4.5, “Access Control, Stage 1: Connection Verification”.)
  • One account has a username of admin and no password. This account can be used only by connecting from the local host. It is granted the RELOAD and PROCESS administrative privileges. These privileges allow the admin user to execute the mysqladmin reload, mysqladmin refresh, and mysqladmin flush-xxx commands, as well as mysqladmin processlist . No privileges are granted for accessing any databases. You could add such privileges later by issuing additional GRANT statements.
  • One account has a username of dummy and no password. This account can be used only by connecting from the local host. No privileges are granted. The USAGE privilege in the GRANT statement enables you to create an account without giving it any privileges. It has the effect of setting all the global privileges to 'N'. It is assumed that you will grant specific privileges to the account later.
  • The statements that create accounts with no password will fail if the NO_AUTO_CREATE_USER SQL mode is enabled. To deal with this, use an IDENTIFIED BY clause that specifies a non-empty password.

As an alternative to GRANT, you can create the same accounts directly by issuing INSERT statements and then telling the server to reload the grant tables using FLUSH PRIVILEGES:

shell> mysql --user=root mysql

mysql> INSERT INTO user

    ->     VALUES('localhost','monty',PASSWORD('some_pass'),

    ->     'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');

mysql> INSERT INTO user

    ->     VALUES('%','monty',PASSWORD('some_pass'),

    ->     'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',

    ->     'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',

    ->     '','','','',0,0,0,0);

mysql> INSERT INTO user SET Host='localhost',User='admin',

    ->     Reload_priv='Y', Process_priv='Y';

mysql> INSERT INTO user (Host,User,Password)

    ->     VALUES('localhost','dummy','');

mysql> FLUSH PRIVILEGES;

The reason for using FLUSH PRIVILEGES when you create accounts with INSERT is to tell the server to re-read the grant tables. Otherwise, the changes go unnoticed until you restart the server. With GRANT, FLUSH PRIVILEGES is unnecessary.

The reason for using the PASSWORD() function with INSERT is to encrypt the password. The GRANT statement encrypts the password for you, so PASSWORD() is unnecessary.

The 'Y' values enable privileges for the accounts. Depending on your MySQL version, you may have to use a different number of 'Y' values in the first two INSERT statements. For the admin account, you may also employ the more readable extended INSERT syntax using SET.

In the INSERT statement for the dummy account, only the Host, User, and Password columns in the user table row are assigned values. None of the privilege columns are set explicitly, so MySQL assigns them all the default value of 'N'. This is equivalent to what GRANT USAGE does.

If strict SQL mode is enabled, all columns that have no default value must have a value specified. In this case, INSERT statements must explicitly specify values for the ssl_cipher, x509_issuer, and x509_subject columns.

Note that to set up a superuser account, it is necessary only to create a user table entry with the privilege columns set to 'Y'. user table privileges are global, so no entries in any of the other grant tables are needed.

The next examples create three accounts and give them access to specific databases. Each of them has a username of custom and password of obscure.

To create the accounts with GRANT, use the following statements:

shell> mysql --user=root mysql

mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP

    ->     ON bankaccount.*

    ->     TO 'custom'@'localhost'

    ->     IDENTIFIED BY 'obscure';

mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP

    ->     ON expenses.*

    ->     TO 'custom'@'whitehouse.gov'

    ->     IDENTIFIED BY 'obscure';

mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP

    ->     ON customer.*

    ->     TO 'custom'@'server.domain'

    ->     IDENTIFIED BY 'obscure';

The three accounts can be used as follows:

  • The first account can access the bankaccount database, but only from the local host.
  • The second account can access the expenses database, but only from the host whitehouse.gov.
  • The third account can access the customer database, but only from the host server.domain.

To set up the custom accounts without GRANT, use INSERT statements as follows to modify the grant tables directly:

shell> mysql --user=root mysql

mysql> INSERT INTO user (Host,User,Password)

    ->     VALUES('localhost','custom',PASSWORD('obscure'));

mysql> INSERT INTO user (Host,User,Password)

    ->     VALUES('whitehouse.gov','custom',PASSWORD('obscure'));

mysql> INSERT INTO user (Host,User,Password)

    ->     VALUES('server.domain','custom',PASSWORD('obscure'));

mysql> INSERT INTO db

    ->     (Host,Db,User,Select_priv,Insert_priv,

    ->     Update_priv,Delete_priv,Create_priv,Drop_priv)

    ->     VALUES('localhost','bankaccount','custom',

    ->     'Y','Y','Y','Y','Y','Y');

mysql> INSERT INTO db

    ->     (Host,Db,User,Select_priv,Insert_priv,

    ->     Update_priv,Delete_priv,Create_priv,Drop_priv)

    ->     VALUES('whitehouse.gov','expenses','custom',

    ->     'Y','Y','Y','Y','Y','Y');

mysql> INSERT INTO db

    ->     (Host,Db,User,Select_priv,Insert_priv,

    ->     Update_priv,Delete_priv,Create_priv,Drop_priv)

    ->     VALUES('server.domain','customer','custom',

    ->     'Y','Y','Y','Y','Y','Y');

mysql> FLUSH PRIVILEGES;

The first three INSERT statements add user table entries that allow the user custom to connect from the various hosts with the given password, but grant no global privileges (all privileges are set to the default value of 'N'). The next three INSERT statements add db table entries that grant privileges to custom for the bankaccount, expenses, and customer databases, but only when accessed from the proper hosts. As usual when you modify the grant tables directly, you must tell the server to reload them with FLUSH PRIVILEGES so that the privilege changes take effect.

If you want to give a specific user access from all machines in a given domain (for example, mydomain.com), you can issue a GRANT statement that uses the “%” wildcard character in the host part of the account name:

mysql> GRANT ...

    ->     ON *.*

    ->     TO 'myname'@'%.mydomain.com'

    ->     IDENTIFIED BY 'mypass';

To do the same thing by modifying the grant tables directly, do this:

mysql> INSERT INTO user (Host,User,Password,...)

    ->     VALUES('%.mydomain.com','myname',PASSWORD('mypass'),...);

mysql> FLUSH PRIVILEGES;

Previous / Next / Up / Table of Contents



User Comments

Posted by Jim Dennis on January 18 2005 9:05pm

[Delete] [Edit]

WARNING: ~/.mysql_history shows any PASSWORD('xxx') calls.

Just a note to admins and users out there; be sure to chmod
0600 your ~/.mysql_history as well as any ~/.my.cnf files.
Otherwise anyone with a local account might be able to read any
of your GRANT and SET PASSWORD statements.

Posted by Max on August 5 2006 6:12pm

[Delete] [Edit]

Indeed one solution to your password problem could lie in the value of 'host'.
Check it out by issuing "SELECT user()" using different interfaces (CLI, web server), and giving different values for 'host'.

On one server where I'm not admin but I have to work on, there happen strange things :
sometimes host='' defaults to 'localhost', sometimes to 'localhost.localdomain' (on the same mysql server !!) and the two corresponding accounts can have different passwords.
Or one may need a password, and the other one not.

Even worse, on this server:
<?php

mysql_connect('localhost'); 
print_rmysql_fetch_assocmysql_query"SELECT user()"))) 
?>
shows:
Array ( [user()] => nobody@localhost.localdomain )

i.e. it is IMPOSSIBLE to connect from PHP with host='localhost', while the CLI shows that there exist two different users,
nobody@localhost and nobody@localhost.localdomain
(and its the same for user='root'! and they have different privileges!)

In general, phpMyAdmin will do what you need for your PHP scripts, because it uses the same interface (as long as they run on the same web server), while the CLI does not (but allows for more direct and less 'default prone' access to the db server).

Also keep in mind the VARIOUS security risks using phpMyAdmin (among others, both Apache HTTP_AUTH passwords and MySQL passwords transit in clear text in the POST data, and might be available to 'everybody' as global variables (eg. if register_globals is on) ...) !

Posted by jon doe on October 27 2006 7:42am

[Delete] [Edit]

Say you wanted to add a couple of users,
but wanted to prevent access to the entire db to one of them -

mysql> grant all on DATABASENAME to USERNAME1 identified by 'PASSWORD';

This allows them all privs, but only to that database.

To restrict privs:
mysql>grant select (FIELD1, FIELD2) on DATABASENAME to USERNAME2 identified by 'PASSWORD';


 

5.5.3. Removing User Accounts from MySQL

To remove an account, use the DROP USER statement, which is described in Section 12.5.1.2, “DROP USER Syntax”.

12.5.1.2. DROP USER Syntax

DROP USER user [, user] ...

The DROP USER statement removes one or more MySQL accounts. To use it, you must have the global CREATE USER privilege or the DELETE privilege for the mysql database. Each account is named using the same format as for the GRANT statement; for example, 'jeffrey'@'localhost'. If you specify only the username part of the account name, a hostname part of '%' is used. For additional information about specifying account names, see Section 12.5.1.3, “GRANT Syntax”.

DROP USER as present in MySQL 5.0.0 removes only accounts that have no privileges. In MySQL 5.0.2, it was modified to remove account privileges as well. This means that the procedure for removing an account depends on your version of MySQL.

As of MySQL 5.0.2, you can remove an account and its privileges as follows:

DROP USER user;

The statement removes privilege rows for the account from all grant tables.

Before MySQL 5.0.2, DROP USER serves only to remove account rows from the user table for accounts that have no privileges. To remove a MySQL account completely (including all of its privileges), you should use the following procedure, performing these steps in the order shown:

  1. Use SHOW GRANTS to determine what privileges the account has. See Section 12.5.4.12, “SHOW GRANTS Syntax”.
  2. Use REVOKE to revoke the privileges displayed by SHOW GRANTS. This removes rows for the account from all the grant tables except the user table, and revokes any global privileges listed in the user table. See Section 12.5.1.3, “GRANT Syntax”.
  3. Delete the account by using DROP USER to remove the user table row.

Important

DROP USER does not automatically close any open user sessions. Rather, in the event that a user with an open session is dropped, the statement does not take effect until that user's session is closed. Once the session is closed, the user is dropped, and that user's next attempt to log in will fail. This is by design.

DROP USER does not automatically delete or invalidate any database objects that the user created. This applies to tables, views, stored routines, and triggers.

 


 

5.5.4. Limiting Account Resources

One means of limiting use of MySQL server resources is to set the max_user_connections system variable to a non-zero value. However, this method is strictly global, and does not allow for management of individual accounts. In addition, it limits only the number of simultaneous connections made using a single account, and not what a client can do once connected. Both types of control are of interest to many MySQL administrators, particularly those working for Internet Service Providers.

In MySQL 5.0, you can limit the following server resources for individual accounts:

  • The number of queries that an account can issue per hour
  • The number of updates that an account can issue per hour
  • The number of times an account can connect to the server per hour

Any statement that a client can issue counts against the query limit. Only statements that modify databases or tables count against the update limit.

From MySQL 5.0.3 on, it is also possible to limit the number of simultaneous connections to the server on a per-account basis.

Before MySQL 5.0.3, an “account” in this context is assessed against the actual host from which a user connects. Suppose that there is a row in the user table that has User and Host values of usera and %.example.com, to allow usera to connect from any host in the example.com domain. If usera connects simultaneously from host1.example.com and host2.example.com, the server applies the account resource limits separately to each connection. If usera connects again from host1.example.com, the server applies the limits for that connection together with the existing connection from that host.

As of MySQL 5.0.3, an “account” is assessed as a single row in the user table. That is, connections are assessed against the Host value in the user table row that applies to the connection. In this case, the server applies resource limits collectively to all connections by usera from any host in the example.com domain. The pre-5.0.3 method of accounting may be selected by starting the server with the --old-style-user-limits option.

As a prerequisite for using this feature, the user table in the mysql database must contain the resource-related columns. Resource limits are stored in the max_questions, max_updates, max_connections, and max_user_connections columns. If your user table doesn't have these columns, it must be upgraded; see Section 4.4.9, “mysql_upgrade — Check Tables for MySQL Upgrade”.

To set resource limits with a GRANT statement, use a WITH clause that names each resource to be limited and a per-hour count indicating the limit value. For example, to create a new account that can access the customer database, but only in a limited fashion, issue this statement:

mysql> GRANT ALL ON customer.* TO 'francis'@'localhost'

    ->     IDENTIFIED BY 'frank'

    ->     WITH MAX_QUERIES_PER_HOUR 20

    ->          MAX_UPDATES_PER_HOUR 10

    ->          MAX_CONNECTIONS_PER_HOUR 5

    ->          MAX_USER_CONNECTIONS 2;

The limit types need not all be named in the WITH clause, but those named can be present in any order. The value for each per-hour limit should be an integer representing a count per hour. If the GRANT statement has no WITH clause, the limits are each set to the default value of zero (that is, no limit). For MAX_USER_CONNECTIONS, the limit is an integer indicating the maximum number of simultaneous connections the account can make at any one time. If the limit is set to the default value of zero, the max_user_connections system variable determines the number of simultaneous connections for the account.

To set or change limits for an existing account, use a GRANT USAGE statement at the global level (ON *.*). The following statement changes the query limit for francis to 100:

mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'

    ->     WITH MAX_QUERIES_PER_HOUR 100;

This statement leaves the account's existing privileges unchanged and modifies only the limit values specified.

To remove an existing limit, set its value to zero. For example, to remove the limit on how many times per hour francis can connect, use this statement:

mysql> GRANT USAGE ON *.* TO 'francis'@'localhost'

    ->     WITH MAX_CONNECTIONS_PER_HOUR 0;

Resource-use counting takes place when any account has a non-zero limit placed on its use of any of the resources.

As the server runs, it counts the number of times each account uses resources. If an account reaches its limit on number of connections within the last hour, further connections for the account are rejected until that hour is up. Similarly, if the account reaches its limit on the number of queries or updates, further queries or updates are rejected until the hour is up. In all such cases, an appropriate error message is issued.

Resource counting is done per account, not per client. For example, if your account has a query limit of 50, you cannot increase your limit to 100 by making two simultaneous client connections to the server. Queries issued on both connections are counted together.

Queries for which results are served from the query cache do not count against the MAX_QUERIES_PER_HOUR limit.

The current per-hour resource-use counts can be reset globally for all accounts, or individually for a given account:

  • To reset the current counts to zero for all accounts, issue a FLUSH USER_RESOURCES statement. The counts also can be reset by reloading the grant tables (for example, with a FLUSH PRIVILEGES statement or a mysqladmin reload command).
  • The counts for an individual account can be set to zero by re-granting it any of its limits. To do this, use GRANT USAGE as described earlier and specify a limit value equal to the value that the account currently has.

Counter resets do not affect the MAX_USER_CONNECTIONS limit.

All counts begin at zero when the server starts; counts are not carried over through a restart.


 

5.5.5. Assigning Account Passwords

Passwords may be assigned from the command line by using the mysqladmin command:

shell> mysqladmin -u user_name -h host_name password "newpwd"

The account for which this command resets the password is the one with a user table row that matches user_name in the User column and the client host from which you connect in the Host column.

Another way to assign a password to an account is to issue a SET PASSWORD statement:

mysql> SET PASSWORD FOR 'jeffrey'@'%' = PASSWORD('biscuit');

Only users such as root that have update access to the mysql database can change the password for other users. If you are not connected as an anonymous user, you can change your own password by omitting the FOR clause:

mysql> SET PASSWORD = PASSWORD('biscuit');

You can also use a GRANT USAGE statement at the global level (ON *.*) to assign a password to an account without affecting the account's current privileges:

mysql> GRANT USAGE ON *.* TO 'jeffrey'@'%' IDENTIFIED BY 'biscuit';

Although it is generally preferable to assign passwords using one of the preceding methods, you can also do so by modifying the user table directly:

  • To establish a password when creating a new account, provide a value for the Password column:

·         shell> mysql -u root mysql

·         mysql> INSERT INTO user (Host,User,Password)

·             -> VALUES('%','jeffrey',PASSWORD('biscuit'));

·         mysql> FLUSH PRIVILEGES;

  • To change the password for an existing account, use UPDATE to set the Password column value:

·         shell> mysql -u root mysql

·         mysql> UPDATE user SET Password = PASSWORD('bagel')

·             -> WHERE Host = '%' AND User = 'francis';

·         mysql> FLUSH PRIVILEGES;

When you assign an account a non-empty password using SET PASSWORD, INSERT, or UPDATE, you must use the PASSWORD() function to encrypt it. PASSWORD() is necessary because the user table stores passwords in encrypted form, not as plaintext. If you forget that fact, you are likely to set passwords like this:

shell> mysql -u root mysql

mysql> INSERT INTO user (Host,User,Password)

    -> VALUES('%','jeffrey','biscuit');

mysql> FLUSH PRIVILEGES;

The result is that the literal value 'biscuit' is stored as the password in the user table, not the encrypted value. When jeffrey attempts to connect to the server using this password, the value is encrypted and compared to the value stored in the user table. However, the stored value is the literal string 'biscuit', so the comparison fails and the server rejects the connection:

shell> mysql -u jeffrey -pbiscuit test

Access denied

If you assign passwords using the GRANT ... IDENTIFIED BY statement or the mysqladmin password command, they both take care of encrypting the password for you. In these cases, using PASSWORD() function is unnecessary. .5.6. Keeping Your Password Secure

On an administrative level, you should never grant access to the user grant table to any non-administrative accounts.

When you run a client program to connect to the MySQL server, it is inadvisable to specify your password in a way that exposes it to discovery by other users. The methods you can use to specify your password when you run client programs are listed here, along with an assessment of the risks of each method:

  • Use a -pyour_pass or --password=your_pass option on the command line. For example:

·         shell> mysql -u francis -pfrank db_name

This is convenient but insecure, because your password becomes visible to system status programs such as ps that may be invoked by other users to display command lines. MySQL clients typically overwrite the command-line password argument with zeros during their initialization sequence. However, there is still a brief interval during which the value is visible. On some systems this strategy is ineffective, anyway, and the password remains visible to ps. (SystemV Unix systems and perhaps others are subject to this problem.)

  • Use the -p or --password option with no password value specified. In this case, the client program solicits the password from the terminal:

·         shell> mysql -u francis -p db_name

·         Enter password: ********

The “*” characters indicate where you enter your password. The password is not displayed as you enter it.

It is more secure to enter your password this way than to specify it on the command line because it is not visible to other users. However, this method of entering a password is suitable only for programs that you run interactively. If you want to invoke a client from a script that runs non-interactively, there is no opportunity to enter the password from the terminal. On some systems, you may even find that the first line of your script is read and interpreted (incorrectly) as your password.

  • Store your password in an option file. For example, on Unix you can list your password in the [client] section of the .my.cnf file in your home directory:

·         [client]

·         password=your_pass

If you store your password in .my.cnf, the file should not be accessible to anyone but yourself. To ensure this, set the file access mode to 400 or 600. For example:

shell> chmod 600 .my.cnf

Section 4.2.2.2, “Using Option Files”, discusses option files in more detail.

  • Store your password in the MYSQL_PWD environment variable. This method of specifying your MySQL password must be considered extremely insecure and should not be used. Some versions of ps include an option to display the environment of running processes. If you set MYSQL_PWD, your password is exposed to any other user who runs ps. Even on systems without such a version of ps, it is unwise to assume that there are no other methods by which users can examine process environments. See Section 2.4.20, “Environment Variables”.

All in all, the safest methods are to have the client program prompt for the password or to specify the password in a properly protected option file.

NotePASSWORD() encryption is different from Unix password encryption. See Section 5.5.1, “MySQL Usernames and Passwords”.

 

Posted by '김용환'
,

mysql에서 row를 세로로 보기

아따 잼난다~

 

mysql> select * from user \G;

 

 

 *************************** 23. row ***************************
                 Host: 111.111.111.111
                 User: dd
             Password: dagd
          Select_priv: Y
          Insert_priv: Y
          Update_priv: Y
          Delete_priv:
          Create_priv: Y
            Drop_priv: Y
          Reload_priv: Y
        Shutdown_priv: Y
         Process_priv: Y
            File_priv: Y
           Grant_priv: N
      References_priv: N
           Index_priv: N
           Alter_priv: N
         Show_db_priv: N
           Super_priv: N
Create_tmp_table_priv: N
     Lock_tables_priv: N
         Execute_priv: N
      Repl_slave_priv: N
     Repl_client_priv: N
     Create_view_priv: N
       Show_view_priv: N
  Create_routine_priv: N
   Alter_routine_priv: N
     Create_user_priv: N
             ssl_type:
           ssl_cipher:
          x509_issuer:
         x509_subject:
        max_questions: 0
          max_updates: 0
      max_connections: 0
 max_user_connections: 0
23 rows in set (0.00 sec)

Posted by '김용환'
,