MySQL 대용량 데이터베이스 책 읽고 있는데,

---------------------------------------------
no                        이름
---------------------------------------------
1                          하하하
2                          알찬돌삐
null                      히히히


라고 되어있을때.

SELECT COUNT(no) FROM table 을 할 경우.

2 를 반환합니다.

전 보통

SELECT COUNT(0) FROM table 을 쓰는데,

null 이 올수 없는 컬럼 (0) 이 count 함수안에 올 경우

내부적으로 COUNT(*) 으로 변환되다고 하네요.

COUNT(no) 를 하면 no 에서 null 아닌 것을 카운트하며,

COUNT(*) 를 할 경우 전체 컬럼을 세는것이 아니라....

행의 갯수만 세개 된다고 합니다....




이제까지 COUNT(*) 은 나쁘다 라고 알고 있던것에 대한걸 뒤집는것 같네요.
Posted by 알찬돌삐

댓글을 달아 주세요

MySQL 서버 최적화를 위한 Configure 의 설정값에 대하여 잘 설명되어 있는 문서입니다.



출처 : http://zerone.hanyang.ac.kr

Posted by 알찬돌삐

댓글을 달아 주세요

앞의 강좌에서 기본적인 모니터링 방법 및 Conection, Memory 튜닝에 대하여 소개하였습니다. 그러나 show status, show variables 명령어 만으로는 지속적으로 MySQL DB Server 상태를 모니터링 하기에는 불편한 점이 많습니다.

그래서 이번 강좌에는 "MySQL Administrator" 프로그램을 이용하여 효과적으로 모니터링하는 방법에 대하여 소개하도록 하겠습니다.

가. 설치

  1. http://www.mysql.com/products/tools/ 에서 MySQL Administrator 프로그램을 다운로드 받는다. 
    이번 강좌에서는 모니터링에 대한 설명이기 원도우용을 다운로드 받아 개인 PC에 설치하도록 하겠습니다. 서버에 직접 설치할 경우는 서버 OS에 맞는 버전을 다운로드 받아 설치하시면 됩니다.
  2. 다운로드 받은 mysql-administrator-x.x.x-win.msi 를 실행시킨다.
  3. 설치마법사에 따라서 설치한다.
  4. 설치가 완료되면 "시작 > 프로그램 > MySQL > MySQL Administrator" 메뉴가 생성되고 이를 통해 MySQL Administrator 실행한다.
  5. 접속하려는 MySQL Server의 Server Host, Username,Password를 입력한다.

    MySQL Administrator

  6. MySQL Administrator를 통해서 접속한 MySQL 서버에 대한 Server Information, User Administration, Health 등의 정보를 보실 수 있습니다.

    MySQL Administrator

나. MySQL DB Server 상태 모니티링

MySQL Administrator는 Health 메뉴를 통해 Connection Health, Memory Health 정보를 Graph로 동적으로 조회하여 볼 수 있는 기능과 Status Variables, System Variables를 계층적으로 구성해 놓아 손쉽게 해당 정보를 조회하여 볼 수 있습니다.

1. Connection Health 

MySQL Administrator

  • Connection Usage : 최대 동시 접속자 대비 현재 접속율( threads_connected / max_connections )
  • Traffic : Status 중 bytes_sent 값에 대한 정보
  • Number of SQL Queries: Status 중 com_select 값에 대한 정보

     ※ 각 Graph에 대한 자세한 정보는 Graph위에서 마우스 오른쪽키를 클릭 후 "Edit Graph" 을 이용하시면 됩니다.

2. Memory Health

MySQL Administrator

  • Query Cache Hitrate : SQL 구문 및 결과에 대한 Query Cache의 재 사용률로써, Hitrate가 높을수록 성능이 좋다고 생각하시면 됩니다.
  • Key Efficiency : 수직바는 key buffer의 사용량( [Key_blocks_used]*[key_cache_block_size] ) 이며, 선 그래프는 100-(^[Key_reads]/^[Key_read_requests])*100 로써 Hitrate가 작을수록 효율이 좋은 것입니다.

3. System Variables & System Variables

MySQL Administrator

다. 사용자 Health 그래프 만들기

Cache Miss Rate(%) =  Threads_created / Connections * 100 을 Graph를 통해서 모니터링 해 보겠습니다. 

  1. "Connection Health" 탭을 선택한다.
  2. 아래와 같이 마우스오른쪽키를 이용하여 "Add Group" 을 통해 그룹을 생성한다. Group Cation은 Cache Miss Rate로 입력한다.

    MySQL Administrator

  3. 2번과 동일한 방법으로 해당 Group 위에서 마우스오른쪽키를 이용하여 "Add Graph" 를 클릭한다.
  4. 아래와 같이 Value formula 와 Max. Formula 등의 값을 설정해 준다.

    MySQL Administrator

  5. Cache Miss Rate(%) 값을 모니터링 후에  thread_cache_size 값을 최적화 시킨다.

    MySQL Administrator



Posted by 알찬돌삐

댓글을 달아 주세요

MySQL Database의 경우 Oracle 이나 MS SQL Server에 비해서 대용량의 자료를 처리하는 경우가 적기에 튜닝에 필요성이 적은 것 같습니다. 그러나 웹이라는 환경은 많은 사용자가 동시에 접속을 할 수 있기에 항상 모니터링과 최적화는 기본이라고 생각합니다.

본 강좌에서는 기본적인 모니터링 방법과 Connection과 Memory 부분에 대한 튜닝 방법을 소개하도록 하겠습니다.

가. 모니터링 및 초기화 명령어

  • show status - MySQL 데이타베이스의 현재 상황
  • show Processlist - MySQL 프로세스 목록
  • show variables - 설정 가능한 모든 변수 목록
  • flush logs - MySQL의 로그파일 초기화
  • flush status - MySQL 상태정보 초기화
  • flush thread - 쓰레드 캐시에 저장된 쓰레드 초기화
  • flush tables - MySQL에 캐싱된 테이블 초기화
  • flush privileges - 권한정보 재 설정

나. Connection 튜닝

1. status

  • Aborted_clients - 클라이언트 프로그램이 비 정상적으로 종료된 수
  • Aborted_connects - MySQL 서버에 접속이 실패된 수
  • Max_used_connections - 최대로 동시에 접속한 수
  • Threads_cached - Thread Cache의 Thread 수
  • Threads_connected - 현재 연결된 Thread 수
  • Threads_created - 접속을 위해 생성된 Thread 수
  • Threads_running - Sleeping 되어 있지 않은 Thread 수

2. system variables

  • wait_timeout - 종료전까지 요청이 없이 기다리는 시간 ( TCP/IP 연결, Shell 상의 접속이 아닌 경우 )
  • thread_cache_size - thread 재 사용을 위한 Thread Cache 수로써, Cache 에 있는 Thread 수보다 접속이 많으면 새롭게 Thread를 생성한다.
  • max_connections - 최대 동시 접속 가능 수

그외에 status 또는 system variables 값은 참고의 Mysql 메뉴얼을 참조해 주십시요.

mysql> show variables like '%max_connection%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 100   |
+-----------------+-------+
1 row in set (0.00 sec)

mysql> show status like '%connect%';
+----------------------+---------+
| Variable_name      | Value   |
+----------------------+---------+
| Aborted_connects  | 3782    |
| Connections          | 2961108 |
| Max_used_connections | 90      |
| Threads_connected    | 1       |
+----------------------+---------+
4 rows in set (0.01 sec)

mysql> show status like '%clients%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| Aborted_clients | 2160  |
+-----------------+-------+
1 row in set (0.00 sec)

mysql> show status like '%thread%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| Delayed_insert_threads | 0     |
| Slow_launch_threads    | 0     |
| Threads_cached         | 7     |
| Threads_connected      | 1     |
| Threads_created        | 1364  |
| Threads_running        | 1     |
+------------------------+-------+
6 rows in set (0.00 sec)

Cache Miss Rate(%) =  Threads_created / Connections * 100
Connection Miss Rate(%) = Aborted_connects / Connections * 100
Connection Usage(%) = Threads_connected / max_connections * 100

위의 경우는 Cache Miss Rate(%) = 0.05%, Connection Miss Rate(%) = 0.12%, Connection Usage(%) = 1%

3. 튜닝

  • Connection Usage(%)가 100% 라면 max_connections 수를 증가시켜 주십시요. Connection 수가 부족할 경우 Too Many Connection Error 가 발생합니다.
  • DB 서버의 접속이 많은 경우는 wait_timeout 을 최대한 적게 (10~20 정도를 추천) 설정하여 불필요한 연결을 빨리 정리하는 것이 좋습니다. 그러나 Connection Miss Rate(%) 가 1% 이상이 된다면 wait_timeout 을 좀 더 길게 잡는 것이 좋습니다.
  • Cache Miss Rate(%) 가 높다면 thread_cache_size를 기본값인 8 보다 높게 설정하는 것이 좋습니다. 일반적으로 threads_connected 가 Peak-time 시 보다 약간 낮은 수치로 설정하는 것이 좋습니다.
  • MySQL 서버는 외부로 부터 접속 요청을 받을 경우 인증을 위해 IP 주소를 호스트네임으로 바꾸는 과정을 수행하여 접속시에 불필요한 부하가 발생하게 됩니다. skip-name-resolve를 설정하시고 접속시에 IP 기반으로 접속을 하게 되면 hostname lookup 과정을 생략하게 되어 좀 더 빠르게 접속을 하실 수 있습니다.

다. Memory 튜닝

1. status

  • key_block_unused - Key Cache에서 사용되고 있지 않은 Block 수
  • key_reads - Key Block 읽기 요청시 Disk을 읽은 수
  • key_read_requests - Key Block 읽기 요청수

2. system variables

  • key_buffer_size - 인덱스를 메모리에 저장하는 버퍼의 크기
  • table_cache - 전체 쓰레드가 사용할 오픈 가능한 테이블 수
  • myisam_sort_buffer_size - 테이블 repair,Alter table,load data에 사용되는 버퍼 메모리 크기
  • join_buffer_size - 조인을 위한 메모리 버퍼 크기
  • record_buffer - 순차적인 검색을 위해 사용되는 메모리 버퍼 크기
  • record_rnd_buffer - order by 절을 사용할 경우 디스크 사용을 피하기 위하여 사용하는 메모리 버퍼 크기
  • sort_buffer - order by 와 group by에 사용되는 메모리 버퍼 크기
  • tmp_table_size - group by 시 디스크를 사용하지 않고 임시 테이블을 만들기 위해 사용되는 메모리 크기
  • key_cache_block_size - block 의 크기(bytes, 기본값 1024)

mysql> show status like '%key%';
+------------------------+-----------+
| Variable_name          | Value     |
+------------------------+-----------+
| Com_preload_keys       | 0         |
| Com_show_keys          | 2945      |
| Handler_read_key       | 365020739 |
| Key_blocks_not_flushed | 0         |
| Key_blocks_unused      | 222601    |
| Key_blocks_used        | 231960    |
| Key_read_requests      | 847204435 |
| Key_reads              | 4195954   |
| Key_write_requests     | 25034738  |
| Key_writes             | 16452136  |
+------------------------+-----------+
10 rows in set (0.00 sec)

Key Buffer Usage = 1 - ((Key_blocks_unused × key_cache_block_size) / key_buffer_size)
Key_reads/Key_read_requests Rate(%) =  Key_reads/Key_read_requests * 100 
Key_reads/Key_read_requests Relative Rate(%) = (1- ^Key_reads/^Key_read_requests) * 100

* ^Key_Reads = Current Key_Rreads - Previous Key_Reads

3. 튜닝

  • key_buffer_size는 총 메모리 크기의 25% 정도의 크기로 설정하는 것이 좋습니다.
  • Key_reads/Key_read_requests Rate(%)은 일반적으로 1%보다 적습니다. 1% 보다 높다면 Key Cache가 아닌 디스크를 읽은 경우가 많다고 판단할 수 있습니다. 또한 Key_reads/Key_reads_requests Relative Rate(%) 값이 지속적으로 90% 이상일 경우는 key_buffer_size가 효율적으로 설정되어 있다고 생각하시면 됩니다. 하지만 데이터베이스가 엄청나게 크거나 여러 데이터를 골고루 많이 읽는 데이터베이스라면 아무리 많은 양의 키 캐시를 설정해도 90% 이상의 적중률을 얻을 수는 없습니다.

라. 적용

system variables은 my.cnf 또는 my.ini 파일을 수정 후 MySQL Server 를 재시작 해 주십시요.

[www@smson www]$ vi /etc/my.cnf  

# The MySQL server
[mysqld]
port            = 3306
socket          = /tmp/mysql.sock
skip-locking
skip-name-resolve
key_buffer = 256M
max_allowed_packet = 1M
table_cache = 256
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache = 8
query_cache_size= 16M
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 8
wait_timeout = 120

~~~

[root@smson mysql]# /usr/local/mysql/share/mysql/mysql.server restart


마. 참고


'Computer > MySQL' 카테고리의 다른 글

MySQL DataBase 서버 튜닝 - MySQL Administrator  (0) 2010/08/16
MySQL DataBase 서버 튜닝 - Connection과 Memory  (0) 2010/08/16
MYSQL Win32 GUI 툴 쓸만한거.  (2) 2008/03/24
DB Designer-Fork  (2) 2007/11/03
Posted by 알찬돌삐

댓글을 달아 주세요

제가 써본게 몇개 안되지만.

상용 제외하고 무료 버전만........

EMS (Lite 버전), Mysql Query Browser 1.1 , SQLyog Community Edition.

다른게 한두개 더 있는거 같은데. 듣보잡에다가 에러 삑삑 나고 해서 바로 지운듯.

EMS Lite 버전 : DB 용량이 100 메가 넘으면 사용 불가.

Mysql Query Browser 1.1 : 쿼리 콘솔창에 한글 입력하면 삑 .DLL 에러 나면서 죽어버림......

SQLyog Community Edition : Enterprise 버전은 상용같은데 커뮤니티 버전은 GPL  이네열.

지금 요거 쓰는데 그럭저럭 쓸만하네열.

한글도 잘 먹히공.

우흥~

아래는 스샷.

링크는 없습니다. 걍 구글이나 다음에서 검색하시면 다운로드 링크 많이 나옴..

사용자 삽입 이미지

사용자 삽입 이미지

사용자 삽입 이미지

Posted by 알찬돌삐

댓글을 달아 주세요

  1. 날코더 2008/04/11 10:59  댓글주소  수정/삭제  댓글쓰기

    토드랑 비슷하군요..호호호..

DB Designer-Fork

Computer/MySQL 2007/11/03 11:54
현재 회사에서

MSSQL 은 엔터프라이즈 관리자를 쓰는데.

Mysql 용은 따로 딱히 쓸만한게 없어서 이전에 DB Designer 를 쓰다가.

뻑이 넘 심해서 ㅠㅠ. 걍 A4 지와 모나미 볼펜으로 대체하다가

이번에 DB Designer-Fork 라는게 있다는걸 PHPSCHOOL 에서 보고

설치..

나름 좋네요......

사용자 삽입 이미지

DB Designer-Fork



Microfost VISIO 나 ER-Win 을 쓰시라는 분에게 한마디.....

땅파면 라이센스비용은 거저나오나요 -_-;

'Computer > MySQL' 카테고리의 다른 글

MYSQL Win32 GUI 툴 쓸만한거.  (2) 2008/03/24
DB Designer-Fork  (2) 2007/11/03
[스크랩] DBMS MySQL SSH 터널링을 통해 연결하기  (0) 2006/12/31
[스크랩] Mysql 에서 변수의 사용......  (0) 2006/12/18
Posted by 알찬돌삐

댓글을 달아 주세요

  1. AgentSmith 2007/11/03 11:56  댓글주소  수정/삭제  댓글쓰기

    좆네요. 광고가~

SSH 터널링(Tunneling) 이란?

SSH Forwarding 이라고도 한다.
ssh 접속을 이용하여 다른 프로그램이 안전하게 사용할수 있도록 포트 포워딩(port forwarding)을 해주는 것이다.
ssh 를 이용하여 암호화 접속을 이용하여 조금더 안전하게 접속할수 있다.
자세한 것은 다음의 참고 사이트를 확인하세요

0. 기본정의
1) DB 서버의 정보는 다음과 같다고 가정한다.
기본적으로 ssh 접속이 가능한 서버일것 (당연한 얘기지만)
IP : 111.111.111.111
SSH 접속 계정 : sshuser (기본포트 22)
DB 접속 계정 : dbuser (기본포트 3306) (포워딩포트 3400)

1. Mysql 서버에서 수행할 작업
mysql -p -uroot
mysql> grant all on *.* to dbuser@127.0.0.1 identified by '패스워드';
Query OK, 0 rows affected (0.02 sec)
mysql> flush privileges;

2. 자체적으로 SSH Tunneling 을 지원하지 않는 경우
1) SecureCRT 로 연결 -> 3) Mysql-Front 연결
혹은
2) Putty 로 연결 -> 3) Mysql-Front 연결

1) SecureCRT
(1) 새로운 Session 생성

사용자 삽입 이미지

(2) SSH2 옵션에서 접속 정보를 입력합니다.
사용자 삽입 이미지


(3) PortForwarding 탭을 엽니다.
Local : 3400 (접속하려는 포트 임의지정가능)
Remote : 3306 (일반적인 mysql 포트)
사용자 삽입 이미지


(4) 확인을 누르면 다음과 같이 됩니다.
사용자 삽입 이미지


2) 한글 Putty의 경우
(1) 새로운 세션을 생성합니다.
사용자 삽입 이미지


(2) 터널링 옵션에서 다음과 같이 설정한다.
원 포트 : 3400 (우리가 나중에 접속할 포트)
대상 : 3306 (Mysql DB 가 기본적으로 사용하는 포트)
사용자 삽입 이미지


(3) 저장을 한다. 빼먹지 말것
사용자 삽입 이미지


3) Mysql-Front 에서 직접 접속하기
(1) Mysql 2.X 버전
호스트 : localhost
사용자 : dbuser (DB로 접속하는 유저)
포트 : 3400
사용자 삽입 이미지


(2) Mysql 3.X 버전
사용자 삽입 이미지


3. 자체적으로 SSH Tunneling 지원하는 경우
1) SQLgate
(1)  SSH 설정을 한다.
호스트 : 111.111.111.111
유저명 : sshuser (ssh로 접속하는 유저)
로컬포트 : 3400 (접속하려는 포트 임의지정가능)
리모트 호스트 : localhost
리모트 포트 : 3306 (일반적인 mysql 포트)
사용자 삽입 이미지


(2) 로그인 정보를 체크한다.
유저명 : dbuser (DB로 접속하는 유저)
서버 IP : localhost
포트 : 3400 (위에서 설정한 포워딩 로컬포트)
사용자 삽입 이미지


출처 : PHPSCHOOL 의 하늘처럼님
Posted by 알찬돌삐

댓글을 달아 주세요

보통 MySQL에서 변수를 쓰려면 다음과 같이 하면 된다.

SET @yesterday := DATE_ADD(DATE(CURDATE()), INTERVAL -1 DAY);


또한 쿼리 내에서 직접 변수에 값을 담으려면 다음과 같이 하면 된다.

SELECT column
INTO @columnVar ...


이런식으로 쿼리만을 모아서 프로그램 짜듯이 procedure하게 짜나간 후 sql파일로 저장해서 사용한다.

여지껏 이렇게 만들어서 사용하고 있는데...
문제가 하나 생겼다
SELECT해온 컬럼값이 없을 경우 에러를 내 뱉으면서 다음 내용으로 넘어가질 않는 것이다.

MYSQL 문법을 뒤져서 겨우 겨우 찾아냈다.

SELECT @columnVar := column ...


이런식으로 하면 에러가 안나면서 변수에 값을 담을 수 있다.



출처 : 체리필터 블로그

Posted by 알찬돌삐

댓글을 달아 주세요

다음의 문서는 제가 지난 1년여의 기간 동안 웹문서 검색엔진 스카우터(http://www.skouter.com)을 개발하고 운영하면서 얻은 경험을 토대로 작성된 문서의 일부입니다. 웹문서 검색엔진 스카우터는 아직은 데모 사이트의 수준이지만 현재 740만개의 웹문서를 인덱싱하고 있습니다.

----------------------------------
*웹문서 검색엔진 기술의 핵심

웹문서 검색엔진 기술에 있어서 핵심적인 부분은 다음의 몇가지로 요약될 수 있다.


1. 인덱싱한 문서의 갯수
현재 한국에서 서비스되고 있는 웹문서 검색엔진들의 경우 인덱싱하고 있는 문서가 보통 1천만에서 4천만개 정도로 추산된다. 이런 점을 고려하면 한국에서 경쟁력있는 웹문서 검색엔진을 서비스하기 위해서는 먼저 1천만개 이상의 웹문서를 인덱싱하는 것이 필수라고 생각된다. 그러나 천만 단위의 웹문서를 인덱싱하기 위해서는 다음과 같은 몇가지의 기술적, 정책적, 비용적 난점이 존재한다.

- 문서의 수집속도
1천만개 이상의 웹문서를 인덱싱하려면 우선 매우 빠른 속도로 문서를 수집하고 처리하는 크롤러(Crawler)가 필요하다. 만약 크롤러가 하루에 10만개의 문서를 수집한다고 가정하면 1천만개의 문서를 수집하기 위해서는 3개월 이상의 시간을 소모해야 한다. 그러나 전체 인덱싱 과정을 완료하기 위해서 3개월 이상의 시간을 소모한다면, 해당 검색엔진에서 검색되는 정보가 3개월 이전의 것일 수 있다는 점에서 문서의 수집속도가 충분히 빠르다고는 말할 수 없다. 현재 국내에 서비스되는 웹문서 검색엔진 중에서 전체 웹문서를 새로이 수집하고 인덱싱을 하는 풀업데이트 작업의 속도가 가장 빠른 검색엔진은 4천만개 이상의 웹문서를 1개월 이내에 풀업데이트를 한다. 그러므로 국내에서 경쟁력 있는 웹문서 검색엔진을 서비스하려면, 물론 목표로 하는 인덱스의 크기에 따라 다르지만, 보통 하루에 1백만개 이상의 웹문서를 수집할 수 있는 크롤러가 필요하다고 생각된다.

- 효율적인 인덱스 구조
현재 대부분의 검색엔진들이 여러가지 이유로 인해서 역인덱스(Inverted-Index) 구조를 사용하고 있는데, 만약 역인덱스 구조를 사용하는 검색엔진이 1천만개의 문서를 저장하고 문서당 평균적으로 100개의 단어를 인덱싱한다면, 전체 인덱스의 데이타 갯수는 약 10억개에 달한다. 이런 크기의 인덱스를 유지하고 검색하려면 데이타의 물리적인 구조 또한 매우 효율적으로 이루어져 있어야 하는데, 구체적으로 말하자면 검색의 경우에는 하드드라이브의 헤드의 움직임을 최소화하는 형태로 데이타의 물리적인 구조가 이루어져 있어야 하며, 새로운 데이타를 입력하는 경우에는 전체 인덱스를 다시 정렬하는 등의 불합리한 과정이 없어야 한다.

- 고성능의 하드웨어
웹문서 검색엔진의 경우 다루는 데이타의 크기가 보통 수십기가바이트가 넘으며 대형 검색엔진의 경우에는 테라바이트 급의 데이타를 다루는 경우도 있다. 이런 크기의 데이타를 빠른 시간내에 처리하려면 먼저 입출력 속도가 빠른 대용량의 저장장치가 있어야 하며, 충분한 크기의 메모리와 빠른 속도의 CPU 역시 필요하다. 제아무리 효율적인 인덱스 구조를 사용하더라도 충분한 하드웨어의 지원이 없다면 천만단위의 웹문서를 인덱싱하고 검색하는 것은 거의 불가능하다.

- 검색대상의 최소화
웹문서 검색엔진은 인터넷에 존재하는 모든 문서를 인덱싱하는 것을 목표로 할 수는 없다. 현재 한국의 대형 커뮤니티 한곳의 게시판에서 나오는 문서의 갯수만 해도 수백만개에 달하는데, 이런 문서들을 모두 인덱싱한다면 인덱스의 크기는 거의 무한정으로 커질 것이며, 인덱스를 검색하는 속도는 검색엔진으로서의 효용가치가 없는 수준까지 느려질 것이다. 그리고 인덱스의 크기가 커질수록 인덱스의 유지에도 많은 시간과 노력과 비용이 소모되게 마련이다. 그러므로 검색엔진의 효용성을 크게 훼손하지 않는 범위에서 인덱싱할 문서의 갯수를 최소화할 수 있는 방법이 필요하다. 여기에는 우선 사용자에게 유용한 문서에 관한 내부적인 정책을 세우고 그에 따라서 사용자에게 유용하다고 판단되는 문서만을 인덱싱하는 방법을 사용할 수 있으며 보조적으로 스팸문서, 중복문서, 유사문서, 내용이 없는 문서의 제거 또는 최소화를 하는 방법이 있겠다.


2. 정확한 랭킹시스템
현재 서비스되고 있는 대부분의 검색엔진은 기본적으로 사용자가 입력한 검색어와 일치하는 단어를 포함한 문서를 검색한다. 그리고 이런 매칭검색에 의한 검색결과를 내부적인 기준에 의해 결정된 정확도, 또는 중요도에 따라서 다시 정렬을 한 결과를 사용자에게 보여준다. 그런데 웹문서 검색엔진의 경우는 그 특성상 인덱싱하고 있는 문서가 매우 많기 때문에 보통 검색결과가 수만에서 수십만에 달하며, 대형 검색엔진이라면 수백만개의 검색결과를 출력하는 경우도 있다. 그러나 대부분의 경우에 있어서 사용자가 원하는 정보는 검색결과의 극히 일부에 지나지 않는다. 따라서 사용자에게 필요한 정보, 사용자가 원하는 정보를 검색결과의 상위에 출력할 수 있는 기능이 웹문서 검색엔진에서는 매우 중요하다. 실제적인 예를 들자면, 만약 사용자가 한국인이라면 대개의 경우 '야후'라는 단어로 검색을 하는 경우에는 kr.yahoo.com 이 최상위에 출력되는 것을 원할 것이고, '옥션'이라는 단어로 검색을 하는 경우에는 www.auction.co.kr 이 최상위에 출력되는 것을 원할 것이다. 그러나 현재 웹에 존재하는 문서 중에서 '야후', '옥션' 등의 단어를 포함한 문서는 헤아릴 수 없을 정도로 많으며 이들 검색어에 해당하는 웹문서 검색엔진의 검색결과 역시 엄청난 숫자이다. 이렇게 많은 검색결과에서 사용자가 원하는 검색결과인 kr.yahoo.com, www.auction.co.kr 을 최상위에 출력하려면 먼저 사용자에게 중요한 문서의 기준에 관한 올바른 정책과 그 정책을 구현한 랭킹시스템이 필요하다. 이때 랭킹시스템이란 사용자의 의도를 파악하는 인공지능이라는 식의 그 실체가 모호한 허황된 프로그램적 장치가 아니고 웹문서 내부에 존재하는 정보와 외부에 존재하지만 해당 문서와 관련있는 정보를 분석하고 그 정보를 토대로 내부적인 기준에 따라서 각 문서의 랭킹을 산출할 수 있는 일련의 논리적인 체계이다. 정확한 랭킹시스템을 구성하기 위해서는 다음과 같은 점을 고려할 수 있다.

- 검색어의 빈도수
검색어의 빈도수에 따라서 검색결과를 정렬하는 것은 매우 전통적인 방법이며, 대부분의 검색엔진에서 채택하고 있는 방법이다. 이 방법은 웹문서 검색엔진이 신뢰할 수 없는 영역을 검색한다는 점에서 많은 문제점을 갖고 있지만 아직까지도 무시할 수는 없는 방법이다. 예를 들자면 어떤 문서에서 '야후'라는 단어가 많이 발견된다면 이 문서가 야후와 관련이 있다고 생각하는 것이 타당하다. 그러나 현재 인터넷에는 검색어의 빈도수 조작을 시도하는 문서가 많기 때문에 검색어의 빈도수를 랭킹에 반영할 수 있는 경우와 그렇지 않은 경우에 관한 제한을 설정하는 것이 필수이다. 실제로 많은 문서들이 웹문서 검색엔진에서의 랭킹을 조작하기 위해서 문서의 내용과는 아무런 관련이 없는 인기있는 검색어를 제목이나 본문에 나열하는 경우가 있다. 따라서 특정한 단어가 일정 횟수 이상 반복이 되는 경우 랭킹에 반영을 하지 않는다던가 하는 형태의 제한이 필요하다.

- 링크의 빈도수
링크의 빈도수를 랭킹에 반영하는 것은 구글의 페이지랭크 알고리즘 이후에 몇몇 검색엔진에서 채택하고 있는 방법인데, 이 방법의 요점은 보다 많이 링크가 되어 있는 사이트가 보다 인기가 있는 사이트라는 것이다. 비록 요즘에 들어서 이런 형태의 알고리즘을 역이용하려는 스팸문서가 많아지기는 했지만 링크의 빈도수의 조작이 검색어의 빈도수 조작보다 어렵다는 점에서, 링크의 빈도수는 아직도 웹문서 검색엔진의 랭킹시스템을 구성하는 데에 있어서 신뢰도가 높은 중요한 요소가 될 수 있다. 그러나 요즘에는 많은 사이트에서 스팸문서를 통해서 링크의 빈도수를 조작하려는 시도를 하기 때문에, 링크의 빈도수를 랭킹에 반영하려면 정당한 링크와 그렇지 않은 링크에 관한 정책을 만들고 이 정책에 따른 제한을 하는 것이 필요하다.

- 링크텍스트의 반영
링크텍스트란 하나의 문서에서 다른 문서를 지칭할 때의 텍스트를 말한다. 즉 kr.yahoo.com 문서의 제목에서 발견되는 '야후' 라는 단어보다 타 사이트에서 kr.yahoo.com 문서를 야후라는 이름으로 링크를 한 경우의 링크텍스트에서 발견되는 '야후'라는 단어가 보다 객관적이라고 판단할 수 있는데, 이 링크텍스트를 저장하고 인덱싱할 수 있다면 랭킹시스템에 매우 중요한 정도로 반영할 수 있을 것이다. 물론 요즘에는 이런 점까지 감안해서 스팸문서가 제작되지만 링크텍스트는 여전히 문서의 내부에서 발견되는 단어보다 신뢰도가 더 높다. 그러나 이런 링크텍스트를 반영하기 위해서는 우선 크롤러에 링크텍스트를 파싱하고 저장할 수 있는 기능이 있어야 하겠다.

- 스팸필터링
웹문서 검색엔진의 개발과 운영을 어렵게 하는 원인은 먼저 검색대상이 너무 많다는 것이며, 그 다음으로는 웹문서 검색엔진이 신뢰할 수 없는 영역을 검색한다는 것이다. 특히 신뢰할 수 없는 영역을 검색한다는 특성은 객관적이고도 신뢰할 수 있는 랭킹시스템을 구성하려는 시도에 가장 큰 난점으로 작용한다. 현재 웹에는 웹문서 검색엔진에서의 랭킹을 조작하기 위해서 갖가지 방법을 동원한 스팸문서가 난무하고 있는데, 요즘의 스팸문서는 날이 갈수록 더 교묘한 방법을 사용하여 랭킹조작을 시도하고 있다. 이런 신뢰할 수 없는 영역을 검색하는 검색엔진이 보다 신뢰할 수 있는 랭킹시스템을 구성하기 위해서는 먼저 스팸문서에 관한 내부적인 정책을 만들고 그 정책에 따른 스팸문서의 필터링을 통해서 웹문서 검색엔진의 검색대상의 신뢰도를 조금이나마 높이는 방법이 있겠다. 그러나 스팸필터링을 지나치게 강력하게 적용하는 경우에는 스팸문서가 아닌 엉뚱한 문서가 검색대상에서 제외되는 결과가 나오므로 적당한 정도의 스팸필터링을 적용하는 것 또한 중요하다.


3. 업데이트 속도
웹문서 검색엔진의 개발과 운영을 어렵게 하는 가장 큰 원인은 데이타가 너무 많다는 것이다. 현재 한국에서 경쟁력있는 웹문서 검색엔진을 서비스하려면 먼저 1천만개 이상의 웹문서를 인덱싱해야 한다. 그러나 1천만개 이상의 웹문서를 수집하고 인덱싱 하는 것은 그리 간단한 문제가 아니며 더욱 문제를 어렵게 하는 것은 웹이 계속해서 변화를 하고 있다는 것이다. 웹에서는 매일 수많은 문서가 추가되고, 변경되고, 삭제되고 있다. 그런데 웹문서 검색엔진이 웹의 변화를 즉각적으로 반영하지 못한다면, 많은 경우에 있어서 웹문서 검색엔진의 검색결과와 실제 웹문서의 정보가 일치하지 않을 것이며, 때로는 이미 삭제된 문서가 검색결과에 포함되는 경우도 나올 것이다. 하지만 현실적으로 웹의 변화를 즉각적으로 반영할 수 있는 웹문서 검색엔진을 만드는 것은 불가능한 일이다. 천만 단위의 문서를 수집하고 인덱싱하는 작업이라면 아무리 빠른 시스템을 사용한다고 하더라도 수시간내에 완료할 수는 없는 것이다. 따라서 현실적으로 웹문서 검색엔진은 웹의 변화를 즉각적으로 반영하는 것을 목표로 하기 보다는 인덱스의 업데이트 주기를 최소화하는 것을 목표로 해야 할 것이다. 업데이트 속도라는 축면에서 충분한 경쟁력을 갖춘 웹문서 검색엔진을 개발하기 위해서는 다음과 같은 점들을 고려할 수 있다.

- 부분 업데이트의 도입
웹문서 검색엔진의 데이타를 업데이트하는 방법으로 가장 단순한 방법은 전체 데이타를 새롭게 수집하고 인덱싱을 하는 풀업데이트이다. 그러나 1천만개 이상의 웹문서를 인덱싱하는 것을 목표로 하는 웹문서 검색엔진이라면, 아무리 빠르고 효율적인 시스템을 사용한다고 하더라도 풀업데이트 방식만으로는 업데이트 속도를 빠르게 하는 것에 한계가 있다. 그리고 풀업데이트를 하는 경우에도, 풀업데이트의 주기가 수일 이내라면 새롭게 수집된 웹문서의 대부분이 기존의 웹문서와 동일한 내용이므로, 웹의 변화를 반영하기 위해서 매번 풀업데이트를 하는 것은 시스템 자원의 낭비인 것이다. 따라서 웹문서 검색엔진의 업데이트 방법으로는 풀업데이트 이외에, 웹에 새롭게 추가되거나 내용이 변경된 문서만을 기존의 인덱스에 추가하거나 변경된 내용을 반영하는 부분 업데이트를 병행하여 사용하는 것이 좋다.

- 부분 업데이트가 가능한 인덱스 구조
원래 인덱스란 보통의 텍스트 자료를 검색이 용이한 구조로 변경을 한 것이며, 대개의 경우에는 여기에 검색속도를 향상시키기 위해서 정렬까지 된 구조이다. 그런데 웹문서 검색엔진의 경우 그 특성상 인덱스의 크기가 매우 크기 마련이다. 1천만개 이상의 웹문서를 인덱싱하는 경우, 물론 각 웹문서 검색엔진의 인덱싱 정책과 인덱스 구조에 따라서 결과가 조금씩 다르겠지만, 보통 그 인덱스의 크기가 수십기가바이트에 달하며 이런 정도 크기의 인덱스를 작성하는 데에는 많은 시간과 노력이 소모된다. 그런데 앞에서 말했다시피 인덱스란 대개의 경우 검색속도를 높이기 위해서 이미 정렬이 된 구조이다. 그리고 이미 정렬이 된 인덱스에 새로운 데이타를 추가 또는 삽입하기 위해서는 엄청난 크기의 데이타를 앞으로 밀고 뒤로 당기는 작업이 필요하다. 이것은 실제에 있어서는 인덱스를 다시 쓰는 작업이 필요하다는 것이다. 그러나 빠른 시간 내에 부분 업데이트가 가능하려면 이런 식으로 인덱스를 지우고 다시 쓴다는 방법은 매우 비효율적이다. 따라서 부분적인 변경을 빠르게 반영할 수 있는 인덱스 구조가 필요한 것이다.

- 부분 업데이트 대상의 최소화
인덱스의 부분적인 업데이트가 가능하다고 하더라도 웹문서 검색엔진이 웹의 추가되거나 변경된 내용을 모두 반영하는 것을 목표로 할 수는 없다. 웹에는 매일 수많은 문서가 추가되고, 변경되고, 삭제되는데 이런 웹의 변화를 무제한적으로 부분 업데이트에 반영한다면 부분 업데이트 대상이 되는 웹문서는 수백만개에 달할 수도 있으며 이것은 부분 업데이트의 속도를 크게 저하시킨다. 따라서 부분 업데이트 대상의 제한을 통해서 부분 업데이트 대상의 최소화를 하는 것이 필요하다. 부분 업데이트 대상의 최소화는 내부적으로 부분 업데이트에 반영할 문서와 그렇지 않은 문서에 관한 정책을 만들고 그 정책에 따라서 특정한 조건에 해당하는 웹문서만을 크롤링하고 인덱싱하는 방법으로 이루어질 수 있다. 보다 실제적인 예를 들자면, 대형 포탈사이트나 뉴스사이트와 같이 대부분의 사용자들에게 인기가 있으며, 매일 많은 정도의 업데이트가 이루어지는 사이트에서 추가되거나 변경되는 문서의 경우에는 부분 업데이트에 반영하는 것이 좋다고 가정할 수 있다.

출처 : phpschool.com
Posted by 알찬돌삐

댓글을 달아 주세요

# root암호설정 - root로 로그인하여 해야함
% mysqladmin -u root password '변경암호'
% mysqladmin -u root -p기존암호 password '변경암호'


root암호변경설정
PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !
This is done with:
/usr/bin/mysqladmin -u root -p password 'new-password'
/usr/bin/mysqladmin -u root -h ns.dbakorea.pe.kr -p password 'new-password'


DB작업
DB생성: mysql> create database DB명 ( or % mysqladmin -u root -p create DB명 )
DB삭제: mysql> drop database DB명
DB사용: mysql> use DB명 (엄밀히 말하자면, 사용할 'default database'를 선택하는 것이다.)
DB변경: mysql> alter database db명 DEFAULT CHARACTER SET charset (4.1이상에서만 available)

MySQL 연결
mysql -u 사용자 -p DB명 ( or % mysqladmin -u root -p drop DB명 )

데이터파일 실행(sql*loader기능)
mysql>load data infile "데이터파일" into table 테이블명 ;
데이터파일에서 컬럼구분은 탭문자, Null값은 /n로 입력
데이터파일의 위치는 /home/kang/load.txt 와 같이 절대경로로 지정할것.

질의 파일 실행
쉘프롬프트상에서
mysql -u 사용자 -p DB명 < 질의파일
or
mysql프롬프트상에서
mysql> source 질의파일

쉘프롬프트상에서 질의 실행
dbakorea@lion board]$ mysql mysql -u root -pxxxx -e \
> "INSERT INTO db VALUES(
> 'localhost', 'aaa', 'aaa',
> 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y')"


사용자 생성 & 사용자에게 DB할당
shell> mysql --user=root -p mysql

mysql> INSERT INTO user VALUES('localhost','사용자',PASSWORD('비밀번호'),'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO user VALUES('%','사용자',PASSWORD('비밀번호'),'Y','Y','Y','Y','Y','Y','Y','Y','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 ('localhost','DB명','사용자','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('%','DB명','사용자','Y','Y','Y','Y','Y','Y');

mysql> FLUSH PRIVILEGES; (or shell prompt: mysqladmin -u root -pxxxx reload)

CASE 2: GRANT명령을 이용한 사용자 생성(이 방법이 권장된다)
kang이라는 DB를 만들고, 이 DB를 아래에서 나열된 권한을 가진 kang이라는 사용자를 생성
create database kang;
grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on kang.* to kang@localhost identified by 'kang';
grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on kang.* to kang@'%' identified by 'kang';

mysql> create database kang;
Query OK, 1 row affected (0.00 sec)

mysql> grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on kang.* to kang@localhost identified by 'kang';
Query OK, 0 rows affected (0.00 sec)

mysql> grant SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on kang.* to kang@'%' identified by 'kang';
Query OK, 0 rows affected (0.01 sec)

mysql>

여러가지 명령정리
mysql> show variables; 서버의 variables(설정사항)출력
mysql> show variables like 'have_inno%' 조건에 맞는 variables만 출력
mysql> show databases; database목록
mysql> show tables; 현재DB의 테이블목록(temporary table은 출력하지 않음)
mysql> show tables from db명; 지정된 db명이 소유한 테이블목록
mysql> show tables like 'mem%'; 조건에 맞는 테이블목록만 출력
mysql> show index from 테이블명; 인덱스 보기
mysql> show columns from 테이블명; 테이블구조(describe 테이블명, explain 테이블명)
mysql> show table status; 현재 DB의 테이블들의 상태(row수,table type,row길이,..)
mysql> show table status from db명; 지정된 DB의 테이블들의 상태(row수,table type,row길이,..)
mysql> show create table 테이블명; 해당 테이블 생성 SQL문 출력
mysql> rename table 테이블1 to 테이블2; 테이블명 변경(ALTER TABLE 테이블1 RENAME TO 테이블2)
mysql> rename table 테이블1 to 테이블2, 테이블3 to 테이블4; rename multiple tables
mysql> rename table db1명.테이블명 to db2명.테이블명; 테이블을 다른 DB로 이동
mysql> alter table 테이블명 add 컬럼명 데이터타입; 컬럼추가
mysql> alter table 테이블명 del 컬럼명; 컬럼제거
mysql> alter table 테이블명 modify 컬럼명 컬럼타입; 컬럼명에 지정된 컬럼타입의 변경
mysql> alter table 테이블명 change old컬럼명 new컬럼명 컬럼타입 컬럼명 변경
mysql> alter table 테이블명 type=innodb; 테이블type변경
mysql> create table 테이블명(..) type=heap min_rows=10000; 10000row를 수용할 수 있을 만큼 메모리할당(heap type이므로)
mysql> select version(); MySQL서버버전 출력
mysql> create table 테이블2 as select * from 테이블1; 테이블1과 동일한 테이블 생성(with 데이터, as는 생략가능)
mysql> create table 테이블2 as select * from 테이블1 where 1=2; 테이블1과 동일한 구조의 테이블 생성(without 데이터, 1=2는 0으로 할수도 있다.)
mysql> insert into 테이블2 select * from 테이블1; 테이블1의 데이터를 테이블2에 insert


테이블이 존재여부 파악
DROP TABLE IF EXISTS 테이블명;
CREATE TABLE 테이블명 (...);
프로그래밍 언어에서 COUNT(*)를 사용하여 질의가 성공하면 테이블이 존재함을 파악할 수 있다.
ISAM, MyISAM의 경우 COUNT(*)가 최적화되어 상관없으나, BDB, InnoDB의 경우 full scan이 발생하므로 사용하지 마라.
대신 select * from 테이블명 where 0; 을 사용하라. 질의가 성공하면 테이블이 존재하는 것이고, 아니면 존재하지 않는 것이다.



접속
mysql {-h 접속호스트} -u 사용자 -p 사용DB
-h로 다른 서버에 존재하는 MySQL접속시 다음과 같이 MySQL DB에 설정해줘야 한다.
mysql> INSERT INTO user VALUES('접근을 허용할 호스트ip','사용자',PASSWORD('비밀번호'),'Y','Y','Y','Y','Y','Y','Y','Y','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('접근을 허용할 호스트ip','사용DB','사용자','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES; or 쉴프롬프트상에서 % mysqladmin -u root -p flush-privileges


검색조건(where)
regular expression을 지원하다니 신기하군..
mysql> select * from work where 열명 regexp "정규표현식";


백업 & 복구
mysqldump {-h 호스트} -u 사용자 -p DB명 > 백업파일
mysql {-h 호스트} -u 사용자 -p DB명 < 백업파일

mysqldump -u root -p --opt db_dbakorea > dbakorea.sql
mysqldump -u root -p --opt db_board | mysql ---host=remote-host -C database (상이한 머쉰)
mysql -u dbakorea -p db_dbakorea < dbakorea.sql

mysqldump -u root -p --opt db_dbakorea | mysql ---host=ns.dbakorea.pe.kr -C db_dbakorea

테이블 생성구문만을 화면에서 보려면 다음과 같이 --no-data를 사용한다. 테이블명을 생략하면 모든 테이블 출력
mysqldump -u 유저명 -p --no-data db명 테이블명

테이블 검사
isamchk

오라클 sysdate와 동일
insert into test values('12', now());

유닉스 time()함수 리턴값 사용
FROM_UNIXTIME(954788684)
UNIX_TIMESTAMP("2001-04-04 :04:04:04")

MySQL 디폴트 DB&로그파일 위치
/var/lib/mysql
/var/lib디렉토리는 여러 프로세스들이 사용하는 데이터를 저장하는 일종의 파일시스템상의 데이터베이스라고 볼 수 있다.

replace
해당 레코드 존재하면 update하고, 존재하지 않는다면 insert한다.(insert문법과 동일)
replace into test values('maddog','kang myung gyu')'

explain
explain 질의문: 지정한 질의문이 어떻게 실행될 건지를 보여줌
mysql> explain select u.uid, u.name, a.name from sm_user u, sm_addr a where u.uid=a.uid;
+-------+------+-----------------+-----------------+---------+-------+------+-------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------+------+-----------------+-----------------+---------+-------+------+-------+
| u | ALL | PRIMARY | NULL | NULL | NULL | 370 | |
| a | ref | sm_addr_uid_idx | sm_addr_uid_idx | 11 | u.uid | 11 | |
+-------+------+-----------------+-----------------+---------+-------+------+-------+
2 rows in set (0.01 sec)


temporary table
크기가 큰 테이블에 있는 subset에 대한 질의라면 subset을 temporary table에 저장한 후 질의하는 것이 더 빠를 경우가 있다.
temporary table는 세션내에서만 유효하고(현재 사용자만이 볼수 있다는 뜻), 세션종료시 자동적으로 drop된다.

create temporary table (...);
create temporary table (...) type=heap; 디스크가 아닌 메모리에 테이블 생성

존재하는 permanent table의 테이블명과 동일하게 생성할 수 있으며,
temporary table은 permanent table보다 우선시되어 처리된다.
4.0.7의 감마버전에서 테스트하면 결과는 약간 달라진다. 버그인건지..

mysql> create table test (id varchar(10));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test values('dbakorea');
Query OK, 1 row affected (0.00 sec)

mysql> create temporary table test(id varchar(10));
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test;
Empty set (0.00 sec)

mysql> drop table test;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test;
+----------+
| id |
+----------+
| dbakorea |
+----------+
1 row in set (0.00 sec)



Table Type에 다른 Files on Disk

ISAM .frm (definition) .ISD (data) .ISM (indexes)
MyISAM .frm (definition) .MYD (data) .MYI (indexes)
MERGE .frm (definition) .MRG (list of constituent MyISAM table names)
HEAP .frm (definition)
BDB .frm (definition) .db (data and indexes)
InnoDB .frm (definition)

보통 mysqldump를 사용하여 백업을 수행하여 다른 DB서버에 데이터를 restore하면 된다.
MySQL은 별다른 작업없이 데이터파일을 단순히 복사(copy)하는 것만으로도 다른 서버에
DB을 이동시킬 수 있다. 하지만, 이런 방식이 지원되지 않는 table type도 있다.

ISAM: machine-dependent format하기때문에..
BDB : .db파일에 이미 테이블위치가 encode되어 있기때문에..
MyISAM, InnoDB, MERGE :가능(machine-independent format)

별다른 지정을 하지 않았다면 디폴트 TABLE type이 MyISAM이므로, 무난히 migration할 수 있다.
floating-point컬럼(FLOAT,DOUBLE)이 있다면 이러한 방식이 실패할 수 도 있다.

쉘에서는 mysql이 되는데 PHP에서 mysql.sock error를 내면서 MySQL이 안되는 경우
mysql.sock은 /tmp 아니면 /var/lib/mysql에 생기게 된다.
나의 경우, /var/lib/mysql에 mysql.sock파일이 있는데 PHP에서는 /tmp에서 찾으려하면서 에러를 발생했다.
/usr/bin/safe_mysqld파일에서 다음과 같이 수정한다.
주석(#)이 달린 것이 원래것이고 그 밑에 있는것이 수정한 것이다.

# MYSQL_UNIX_PORT=${MYSQL_UNIX_PORT:-/var/lib/mysql/mysql.sock}
MYSQL_UNIX_PORT=${MYSQL_UNIX_PORT:-/tmp/mysql.sock}

위와 같이 하니 /usr/bin/mysql이 /var/lib/mysql/mysql.sock에서 소켓파일을 찾으려 했다.
socket file을 지정하는 --socket이라는 옵션으로 다음과 같이 지정하면 된다.

mysql --socket=/tmp/mysql.sock -u dbakorea -p db_test

하지만 mysql실행시마다 이렇게 써줘야한다는 것이 상당히 귀찮다. 옵션이 바로 적용되게 설정하자.
mysql은 설정사항을 다음 3가지 파일에서 검색한다.

/etc/my.cnf global options(MySQL 전체적으로 사용되는 옵션 정의)
mysql-data-dir/my.cnf 특정 DB에 적용되는 option (/var/lib/mysql/my.cnf)
~/.my.cnf 사용자 각각의 설정('~'문자는 사용자의 홈디렉토리는 의미)

/usr/share/mysql디렉토리에 예제가 있으므로 참고한다.
소켓파일의 지정은 다음줄을 넣어주면 된다.

socket = /tmp/mysql.sock


== /etc/my.cnf예 ==
# The following options will be passed to all MySQL clients
[client]
#password = your_password
port = 3306
socket = /tmp/mysql.sock

# Here follows entries for some specific programs

# The MySQL server
[mysqld]
port = 3306
socket = /tmp/mysql.sock



MySQL에서 통계처리시
orderby, groupby 는 sort_buffer를 늘여준다.(show variables)

live table(smslog)에서 모든 질의를 처리하지 말고 summary table에 질의결과를 저장해 재질의 처리한다.
summary table이 heap-type table가 가능한지 확인할 것.

INSERT INTO tblTemp2 (fldID) SELECT tblTemp1.fldOrder_ID FROM tblTemp1 WHERE
tblTemp1.fldOrder_ID > 100;


join이 subselect보다 빠르다.
join시 사용되는 컬럼은 동일한 column type과 길이를 가져야만 최적의 속도를 보장한다.
즉, 동일 column type이지만 길이가 다르다면(char(11), char(10)), 동일한 컬럼도메인으로 변경해주는 것이 좋다.
where의 in은 optimize되어 있으므로 빠르다
insert,select는 동시에 수행가능하다.(어떻게?)
explain으로 질의과정 점검


varchar to/from char
conversion varchar를 char로 변경할 경우 모든 컬럼타입을 동시에 변경해야 한다.
반대의 경우, 하나만 char->charchar변경시 다른 모든 컬럼도 varchar로 변경됨
참.. 특이하구만..

mysql> CREATE TABLE chartbl (name VARCHAR(40), address VARCHAR(80));
Query OK, 0 rows affected (0.05 sec)

mysql> desc chartbl;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name | varchar(40) | YES | | NULL | |
| address | varchar(80) | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
2 rows in set (0.03 sec)

mysql> alter table chartbl modify name char(40);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> desc chartbl;
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| name | varchar(40) | YES | | NULL | |
| address | varchar(80) | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> alter table chartbl modify name char(40), modify address char(80);
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> desc chartbl;
+---------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+-------+
| name | char(40) | YES | | NULL | |
| address | char(80) | YES | | NULL | |
+---------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql>


"For each article, find the dealer(s) with the most expensive price."

표준안
SELECT article, dealer, price
FROM shop s1
WHERE price=(SELECT MAX(s2.price)
FROM shop s2
WHERE s1.article = s2.article);

수정안(최적화)
CREATE TEMPORARY TABLE tmp (
article INT(4) UNSIGNED ZEROFILL DEFAULT '0000' NOT NULL,
price DOUBLE(16,2) DEFAULT '0.00' NOT NULL);

LOCK TABLES shop read;

INSERT INTO tmp SELECT article, MAX(price) FROM shop GROUP BY article;

SELECT shop.article, dealer, shop.price FROM shop, tmp
WHERE shop.article=tmp.article AND shop.price=tmp.price;

UNLOCK TABLES;

DROP TABLE tmp;



========================================================
MySQL 특성정리
========================================================
primary key, foreign key지원
index 지원(15개컬럼, 256byte까지)
MySQL에서의 Stored Script개념 => SQL server language
commit-rollback개념 => lock tables(lock table test write -> 트랜잭션.. -> unlock tables)
컬럼명길이: 64자까지, 컬럼 Alias: 256자까지
not case-sensitive: keywords, functions, column, index명
case-sensitive: database, table, alias명
키워드,함수명은 대소문자구별이 없지만, db명과 table명은 Unix계열이라면 case-sensitive하다.
(이는 오브젝트명이 OS의 fs에 따라 저장되기 때문이다. 서버의 lower_case_table_names 변수를
1로 설정하면 오브젝트명은 모두 소문자로 저장되므로 유닉스-윈도간 호환성을 높일 수 있다.

지원되지 않는 부분:
Stored Procedure(5.0이상부터 지원된다고 함)
View(5.0이상부터 지원된다고 함)
Trigger(5.0이상부터 지원된다고 함)
subquery(4.1이상부터 지원된다고 함)
union, union all(4.0이상부터 지원됨)

[테이블 type에 따른 인덱스 특성]
Index Characteristic ISAM MyISAM HEAP BDB InnoDB
NULL values allowed No Yes As of 4.0.2 Yes Yes
Columns per index 16 16 16 16 16
Indexes per table 16 32 32 31 32
Maximum index row size (bytes) 256 500 500 500/1024 500/1024
Index column prefixes allowed Yes Yes Yes Yes No
BLOB/TEXT indexes allowed No Yes(255 bytes max) No Yes (255 bytes max) No


인덱스 생성
- alter table을 이용한 인덱스 생성이 더 flexible함
- 인덱스명은 생략가능

ALTER TABLE 테이블명 ADD INDEX 인덱스명 (인덱스컬럼);
ALTER TABLE 테이블명 ADD UNIQUE 인덱스명 (인덱스컬럼);
ALTER TABLE 테이블명 ADD PRIMARY KEY (인덱스컬럼);
ALTER TABLE 테이블명 ADD FULLTEXT (인덱스컬럼);

CREATE INDEX 인덱스명 ON 테이블명 (인덱스컬럼);
CREATE UNIQUE INDEX 인덱스명 ON 테이블명 (인덱스컬럼);
CREATE FULLTEXT INDEX 인덱스명 ON 테이블명 (인덱스컬럼);

unique인덱스와 primary key인덱스와의 차이
unique은 null허용하지만, primary key는 null허용 안함
unique은 하나의 테이블에 여러개 올 수 있지만, primary key는 하나만 존재

테이블생성시 지정
CREATE TABLE 테이블명
(
... column declarations ...
INDEX 인덱스명 (인덱스컬럼),
UNIQUE 인덱스명 (인덱스컬럼),
PRIMARY KEY (인덱스컬럼),
FULLTEXT 인덱스명 (인덱스컬럼),
...

);


index prefix 생성
- 컬럼의 전체길이중 일부만 인덱스로 사용
- supported for ISAM, MyISAM, HEAP, and BDB tables, but not for InnoDB tables
- 지정되는 길이는 byte단위가 아닌 charater단위이므로, multi-byte character일 경우 주의
- blob, text 컬럼타입일 경우, index prefix 가 유용(255 길이까지 가능)

CREATE TABLE 테이블명
(
name CHAR(30) NOT NULL,
address CHAR(60) NOT NULL,
INDEX (name(10),address(10))
);


인덱스 삭제
DROP INDEX 인덱스명 ON 테이블명;
ALTER TABLE 테이블명 DROP INDEX 인덱스명;
ALTER TABLE 테이블명 DROP PRIMARY KEY;


outer join

[MySQL]
left outer joing : SELECT t1.*, t2.* FROM t1 LEFT OUTER JOIN t2 ON t1.i1 = t2.i2;
right outer joing: SELECT t1.*, t2.* FROM t1 RIGHT OUTER JOIN t2 ON t1.i1 = t2.i2;

[Oracle]
left outer joing : SELECT t1.*, t2.* FROM t1, t2 where t1.i1 = t2.i2(+);
right outer joing: SELECT t1.*, t2.* FROM t1, t2 where t1.i1(+) = t2.i2;

SELECT
student.name, student.student_id,
event.date, event.event_id, event.type
FROM
student, event
LEFT JOIN score ON student.student_id = score.student_id
AND event.event_id = score.event_id
WHERE
score.score IS NULL
ORDER BY
student.student_id, event.event_id;


:= 문장을 이용한 변수의 설정

현재 dbakorea의 데이터베이스강좌게시판에 등록된 총 게시물은 43개이다. 43개의 강좌를 읽은 수(hit수)는 각각 다르다.
평균 hit수를 구해 보자.

mysql> select @total_hit := sum(hit), @total_record := count(*) from zetyx_board_database;
+------------------------+---------------------------+
| @total_hit := sum(hit) | @total_record := count(*) |
+------------------------+---------------------------+
| 3705 | 43 |
+------------------------+---------------------------+
1 row in set (0.00 sec)

mysql> select @total_hit/@total_record as 평균HIT;
+-----------------+
| 평균HIT |
+-----------------+
| 86.162790697674 |
+-----------------+
1 row in set (0.00 sec)



select substring(subject from 9) from zetyx_board_database where substring(subject, 1, 8) = '[ORACLE]';


보통 상용DBMS들이 row-level locking을 지원한다. 쉽게 말해 레코드단위로 락킹한다는 말이다.
반면, MySQL의 MyISAM 테이블타입은 table-level locking을 사용한다.
쉽게 말하면, insert, update, delete작업은 전체 테이블에 락을 걸고 처리된다는 것이다.
row-level락보다 비효율적이지만,.. MySQL은 빠르기 때문에 이 단점이 상쇄된다.

Compressed MyISAM(packed MyISAM)
정적인 테이블데이터는 압축하여 20-60%정도의 공간을 절약할 수 있다.
Production데이터를 CD로 받아서 차후 디스크에 풀지 않고 CD자체로 바로 사용할 수도 있다.
gzip등으로 백업받으면 이를 푸는 과정이 필요할 것이다.
% myisampack dbakorea.myi

데이터베이스 게시판의 Merge Table에 좀 더 자세한 내용을 적어 두었다.


RAID Table
1개의 테이블은 OS상에 3개의 파일로 구성된다.
스키마파일(.frm), data파일(.myd), index파일(.myi)
MySQL의 RAID테이블은 데이터파일(.myd)을 여러개의 파일들로 구성하는 것이다.

create table raid_test (...)
type=myisam raid_type=striped raid_chunks=4 raid_chunsize=8

테이블을 4개의 데이터파일로 나누고, 8kb단위로(8kb stripe) 라운드로빈 방식으로 write가 이루어진다.

This article comes from dbakorea.pe.kr (Leave this line as is)

출처 : http://www.superuser.co.kr
Posted by 알찬돌삐

댓글을 달아 주세요

  1. mash 2005/05/16 17:03  댓글주소  수정/삭제  댓글쓰기

    호, 요즘 mysql은 레이드테이블까지 되나보군요. join도 좀 확장된것 같고... 손뗀지 오래라 기억이 가물거리는군요.ㅋㅋㅋ