반응형

DB 를 설치해 보자.


먼저 설치를 하기 전에 현재 개발 서버에는 Mysql 3.2X 가 무수히 멀티로 운영중이며, 또한 MySQL 5.0x 버전 또한 설치가 되어 있다.


그렇기에 나는 기존 설치 방식이 아닌 다른 방식으로 설치를 진행할 수 밖에 없었다.



1. my.cnf 생성


이 부분은 앞으로 수정되어야 할 듯싶다.


#my.cnf 를 읽는 순서

#1. /etc/my.cnf파일

#2. /etc/mysql/my.cnf

#3. /usr/local/mysql/etc/my.cnf

#4. ~/.my.cnf


[client]

default-character-set = euckr

#default-collaction-set = euckr_korean_ci #euckr_bin

[mysqld]

user = mysql

port            = 4958

basedir = /usr/local/rmysql

datadir = /usr/local/rmysql/data

tmpdir = /usr/local/rmysql/tmp

socket          = /tmp/rmysql.sock

default-storage-engine = MyIsam

event-scheduler = ON

sysdate-is-now


#######

back_log = 100

max_connections = 300

max_connect_errors = 999999

thread_cache_size = 50

table_open_cache = 400

wait_timeout = 28800


max_allowed_packet = 32M

max_help_table_size = 32M

tmp_table_size = 512K


sort_buffer_size = 128K

join_buffer_size = 128K

read_buffer_size = 128K

read_rnd_buffer_size = 128K


query_cache_size = 32M

query_cache_limit = 2M


group_concat_max_len = 1024


########

######### MyISAM Option

## InnoDB를 사용하지 않고 MyISAM만 사용한다면 key_buffer_size 를 4GB까지 설정

key_buffer_size = 32M

bulk_insert_buffer_size = 32M

myisam_sort_buffer_size = 1M

myisam_max_sort_file_size = 2G

myisam_repair_threads = 1

myisam_recover

ft_min_word_len = 3


##로깅 옵션

pid-file = /usr/local/rmysql/logs/mysqld.pid

log-warnings = 1

log-error = /usr/local/rmysql/logs/mysqld


##General log 사용

general_log = 0

general_log_file = /usr/local/rmysql/logs/general_query.log


log_slow_admin_statements

slow-query-log = 1

long_query_time = 1

slow_query_log_file = /usr/local/rmysql/logs/slow_query.log


##replication option

##if this DB is Master DB then you need to remove #

log-bin = /usr/local/mysql/logs/binary_log

binlog_cache_size = 128K

max_binlog_size = 512M

expire_logs_days = 14

log-bin-trust-function-creators = 1

sync_binlog = 1


##if this DB is Slave DB then you need to remove #

#relay-log = /usr/local/rmysql/logs/relay_log

#relay_log_purge = TRUE

#read_only


##현재 서버가 슬레이브이면서 마스터 MySQL인 경우

##현재 MySQL 서버로 복제되는 쿼리를 바이너리 로그에 저장하려면 아래 주석을 해제

#log-slave-updates


위와 같이 작성 하였지만, 설치가 되지 않았다.


 - ...../rmysql/scripts 에서 처음 DB생성을 시도하였지만 아래와 같은 에러가 발생하였다.

FATAL ERROR: Could not find .//usr/local/rmysql/bin/my_print_defaults


If you compiled from source, you need to run 'make install' to

copy the software into the correct location ready for operation.


If you are using a binary release, you must either be at the top

level of the extracted archive, or pass the --basedir option

pointing to that location.


검색하였더니 scripts 폴더가 아닌 mysql base 위치에서 진행하라고 나와 있었다.(외국 블로그)


그래서 다시 base위치에서 진행을 시도 하였지만...아래와 같이 진행되고 stop 되었다.


Installing MySQL system tables...2016-06-14 15:11:49 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --ex                                                                                       plicit_defaults_for_timestamp server option (see documentation for more details).

2016-06-14 15:11:49 0 [Note] ./bin/mysqld (mysqld 5.6.31-log) starting as process 13591 ...


결국 찾지 못하고 base에 my.cnf 를 설정하기로 했다.(최대한 my.cnf 내용은 간소하게..설치가 목적이라..)


# For advice on how to change settings please see

# http://dev.mysql.com/doc/refman/5.6/en/server-configuration-defaults.html


[mysqld]


# Remove leading # and set to the amount of RAM for the most important data

# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.

# innodb_buffer_pool_size = 128M


# Remove leading # to turn on a very important data integrity option: logging

# changes to the binary log between backups.

# log_bin


# These are commonly set, remove the # and set as required.

# basedir = .....

# datadir = .....

# port = .....

# server_id = .....

# socket = .....


# Remove leading # to set options mainly useful for reporting servers.

# The server defaults are faster for transactions and fast SELECTs.

# Adjust sizes as needed, experiment to find the optimal values.

# join_buffer_size = 128M

# sort_buffer_size = 2M

# read_rnd_buffer_size = 2M


sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES

#default-character-set = euckr  이게 문제였다...

character-set-server = euckr   이렇게 작성해 주었다.


user            = mysql

port            = 4958

socket          = /tmp/rmysql.sock

default-storage-engine  = myisam

event-scheduler = ON

sysdate-is-now


key_buffer_size                 = 32M

bulk_insert_buffer_size = 32M

myisam_sort_buffer_size = 1M

myisam_max_sort_file_size       =       2G

myisam_repair_threads                   =       1

myisam_recover

ft_min_word_len                                         = 3



[root@devDB:/usr/local/rmysql]# ./scripts/mysql_install_db --defaults-file=/usr/local/rmysql/my.cnf --basedir=/usr/local/rmysql --datadir=/usr/local/rmysql/data --explicit_defaults_for_timestamp=on


또 에러 발생...



...

2016-06-14 15:40:33 13684 [Note] InnoDB: 5.6.31 started; log sequence number 0

2016-06-14 15:40:33 13684 [ERROR] /usr/local/rmysql/bin/mysqld: unknown variable 'default-character-set=euckr'

2016-06-14 15:40:33 13684 [ERROR] Aborting


2016-06-14 15:40:33 13684 [Note] Binlog end

2016-06-14 15:40:33 13684 [Note] InnoDB: FTS optimize thread exiting.

2016-06-14 15:40:33 13684 [Note] InnoDB: Starting shutdown...

2016-06-14 15:40:34 13684 [Note] InnoDB: Shutdown completed; log sequence number 1600607

2016-06-14 15:40:34 13684 [Note] /usr/local/rmysql/bin/mysqld: Shutdown complete

OK


To start mysqld at boot time you have to copy

support-files/mysql.server to the right place for your system


PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !

To do so, start the server, then issue the following commands:


  /usr/local/rmysql/bin/mysqladmin -u root password 'new-password'

  /usr/local/rmysql/bin/mysqladmin -u root -h devDB password 'new-password'


Alternatively you can run:


  /usr/local/rmysql/bin/mysql_secure_installation


which will also give you the option of removing the test

databases and anonymous user created by default.  This is

strongly recommended for production servers.


See the manual for more instructions.


You can start the MySQL daemon with:


  cd . ; /usr/local/rmysql/bin/mysqld_safe &


You can test the MySQL daemon with mysql-test-run.pl


  cd mysql-test ; perl mysql-test-run.pl


Please report any problems at http://bugs.mysql.com/


The latest information about MySQL is available on the web at


  http://www.mysql.com


Support MySQL by buying support/licenses at http://shop.mysql.com


WARNING: Found existing config file /usr/local/rmysql/my.cnf on the system.

Because this file might be in use, it was not replaced,

but was used in bootstrap (unless you used --defaults-file)

and when you later start the server.

The new default config file was created as /usr/local/rmysql/my-new.cnf,

please compare it with your file and take the changes you need.


WARNING: Default config file /etc/my.cnf exists on the system

This file will be read by default by the MySQL server

If you do not want to use this, either remove it, or use the

--defaults-file argument to mysqld_safe when starting the server



- 이 부분은 위에서 수정해 주었다. #default-character-set = euckr  이게 문제였다...


이 후 다시 진행을 했더니 제대로 설치가 된 것 같았다.

이제 MySQL 를 실행해 보자


여기서는 아래 사이트를 참고하면서 진행 하였다.

참조 : http://jmkjb.tistory.com/entry/MySQL5621SetupSourceCompile

반응형

'MySQL' 카테고리의 다른 글

[MySQL] 빈로그 지우기 [펌]  (0) 2016.06.16
[MySQL]5.6.31 source 설치 (3) - 완료  (0) 2016.06.15
[MySQL]5.6.31 source 설치  (0) 2016.06.13
[MySQL] Federated Engine (Table) (2) - 마무리  (0) 2016.06.09
[MySQL] Federated Engine (Table)  (1) 2016.06.09
반응형

MySQL 설치를 보면 대부분 간단하게 yum 을 이용한 설치를 알려준다.


MySQL 엔지니어는 안해봤지만, Oracle Engineer를 한 경험상, UI를 통해 설치하는 경우도 대부분이긴 하지만,

단순히 Typicall 이 아닌 Manual 대로 진행하는 경우가 보통이다.

즉, 설정값 들을 수동으로 진행하는 경우가 대부분 이었다.


그래서 나는 단순 설치가 아닌 CMake를 이용한 source 설치를 

물론 책에도 이렇게 진행하는 방식을 알려준다...




MySQL 5.6.31 로 진행하였으며, mysql 홈페이지 가면 찾기가 조금 까다롭다.

해당 페이지를 참조하면서 설치 하였다.

http://jmkjb.tistory.com/entry/MySQL5621SetupSourceCompile


먼저 souce 파일을 다운받아 보자.


현재 테스트 서버는 CentOS 5.6 이다

[root@devDB:/root]#  rpm -qa | grep release

centos-release-5-6.el5.centos.1


http://dev.mysql.com/downloads/mysql/5.6.html#downloads 에서 다운받아 진행했다.

여기서 select platform 을 눌러보면 Source Code가 있는데 선택해서 맞는 OS 에 대해 다운 받으면 된다.

이지 참고를 하면 금방 찾을 수 있을 것이다.

이 후, 책을 참고 하여 진행 하였다.


다운 받은 파일을 압축을 풀어 압축 푼 폴더 내에서 build_target이라는 폴더를 생성한다.

mkdir -p /home/Setup/mysql-5.6.31/build_target


MySQL 5.5부터는 CMake를 이용한 Makefile를 생성 해야 한다.


다만 여기서 책과 다른 점은 SSL 이다. SSL 에 대한 정보는 다음과 같은데,

책에서는 0으로 설정했는데, bundled 로 나는 선택했다.


만약 여기서 에러가 생기면 해당 폴더(여기서는 /home/Setup/mysql-5.6.31/build_target) 를 다 삭제 후에 다시 진행해야한다.

또한 에러 찾기 위해서는 CMakeLists.txt 파일을 열어 찾아 보는 것을 추천한다. 나도 에런 코드 위치 찾아 보니 SSL 관련 된 내용이 있길레 변경을 한 후 진행하였다..


맨 마지막에 done 으로 뜨면 완료 된 것이다.

먼저, 자신이 설치할 위치에 디렉터리 권한 설정 및 가급적 폴더까지 생성하자.

mkdir -p /usr/local/rmysql/bin

mkdir -p /usr/local/rmysql/etc

mkdir -p /usr/local/rmysql/data

...


chown -R root /usr/local/rmysql

chown -R mysql /usr/local/rmysql/data

chown -R mysql /usr/local/rmysql/bin

chown -R mysql /usr/local/rmysql/etc

chgrp -R dba /usr/local/rmysql

...


*CMake 파일 생성 정보


$ cmake .. \

 '-DCMAKE_INSTALL_PREFIX=/usr/local/rmysql' \                //자기에 맞는 경로를 설정하자(mysql 엔진설치 위치)

 '-DWITH_COMMENT=Toto mysql standard x86_64' \

 '-DINSTALL_SBINDIR=/usr/local/rmysql/bin' \

 '-DINSTALL_BINDIR=/usr/local/rmysql/bin' \

 '-DINSTALL_LAYOUT=STANDALONE' \

 '-DMYSQL_DATADIR=/usr/local/rmysql/data' \               //데이터 위치

 '-DSYSCONFDIR=/usr/local/rmysql/etc' \

 '-DINSTALL_SCRIPDIR=/usr/local/rmysql/bin' \

 '-DWITH_INNOBASE_STORAGE_ENGINE=1' \

 '-DWITH_ARCHIVE_STORAGE_ENGINE=1' \

 '-DWITH_BLACKHOE_STORAGE_ENGINE=1' \

 '-DWITH_PERFSCHEMA_STORAGE_ENGIN=1' \

 '-DWITH_PARTITION_STORAGE_ENGINE=1' \

 '-DWITH_FEDERATED_STORAGE_ENGINE=1' \

 '-DENABLE_DEBUG_SYNC=0' \

 '-DENABLED_LOCAL_INFILE=1' \

 '-DENABLED_PROFILING=1' \

 '-DWITH_DEBUG=0' \

 '-DWITH_LIBWRAP=0' \

 '-DWITH_READLINE=1' \

 '-DWITH_SSL=bundled' \

 '-DCMAKE_BUILD_TYPE=RelWithDebInfo' \

 '-DCMAKE_C_FLAGS=-02' \

 '-DCMAKE_CXX_FLAGS=-02'



해당 속성 정보들은 아래와 같다

[펌] http://www.programkr.com/blog/MkjMxADMwYTz.html


  • 지정 설치 파일 설치 경로 때 자주 쓰는 옵션

-DCMAKE_INSTALL_PREFIX=/usr/local/mysql   # 지정 설치 경로 (기본 바로/usr/local/mysql)
-DMYSQL_DATADIR=/data/mysql               # mysql 데이터 파일 경로
-DSYSCONFDIR=/etc                         # 프로필 경로
  • 컴파일 과정 중에 다른 저장소 엔진 사용하기

-DWITH_INNOBASE_STORAGE_ENGINE=1          # INNOBASE 저장소 엔진 사용하기
-DWITH_ARCHIVE_STORAGE_ENGINE=1           # 자주 사용하는 로그 및 집계 분석 한다, 지원하지 않는 인덱스
-DWITH_BLACKHOLE_STORAGE_ENGINE=1         # 블랙홀 저장소 엔진
  • 컴파일 과정에서 일부 저장소 엔진, 취소

-DWITHOUT_<ENGINE>_STORAGE_ENGINE=1
예제 다음과 같다: 
-DWITHOUT_EXAMPLE_STORAGE_ENGINE=1
-DWITHOUT_FEDERATED_STORAGE_ENGINE=1
-DWITHOUT_PARTITION_STORAGE_ENGINE=1
  • 컴파일 들어갈 과정에서 기능 활성화 명령 소개

-DWITH_READLINE=1       # 지원 대량 가져오기 mysql 데이터
-DWITH_SSL=system       # mysql 지원 ssl 회화 구현 기반 ssl 데이터 회답하다
-DWITH_ZLIB=system      # 압축 라이브러리
-DWITH_LIBWRAP=0        # WRAP 실현할 수 있는지 기반 접근 제어
  • 기타 기능 명령

-DMYSQL_TCP_PORT=3306                   # 기본 포트
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock       # 기본 소켓 파일 경로
-DENABLED_LOCAL_INFILE=1                # LOCAL_INFILE 기능 사용 여부
-DEXTRA_CHARSETS=all                    # 혹시 지원 추가 문자 집합
-DDEFAULT_CHARSET=utf8                  # 기본 인코딩 메커니즘
-DDEFAULT_COLLATION=utf8_general_ci     # 기본 언어 데이터 정렬
-DWITH_DEBUG=0                          # DEBUG 기능 설정
-DENABLE_PROFILING=1                    # 성능 처리 기능 사용 여부


이것까지 완료 되었다면, 이제 Install를 진행하자.


$ make && make install


이렇게 치면 다음과 같이 설치가 진행 되는 것을 확인할 수 있다.



옆에 %가 나와서 보기가 좋다.

에러가 난 적은 없지만..에러가 어떻게 하면 에러가 찾을 수 있을지는 나중으로........나도 찾아봐야 하기에;;;ㅠ


이제 DB를 생성해 보자.


vi /etc/RMy.cnf 라는 이름으로 생성해 보자.



반응형
반응형


추가로 확인된 부분이 있어서 정리해 보았다.


Federated 테이블 생성 시 마지막에 remote DB의 접속 정보를 작성하게 된다.


간단하게 앞에서 만들어 본 federated_table 에 대해서 script 를 확인해 보자

(보기 편하게 \G 를 붙여 세로로 보자)

mysql > show create table fedrated_table\G


아무리 회사 테스트DB정보이지만 모자이크...-_-



다른 부분은 전부 필요없고, 맨 하단에 이렇게 IP 정보와 포트 정보, 계정 정보 등이 모두 표기가 된다......(모자이크지만....)


그래서 분명 보안상에 문제가 될 수 있다.


그렇기에 다음과 같이 Server를 Syntax(synonym??) 으로 만들어 진행하면 보안적인 부분을 해결할 수 있다.


Syntax 만드는 구문이다.


CREATE SERVER server_name
    FOREIGN DATA WRAPPER wrapper_name
    OPTIONS (option [, option] ...)

option:
    { HOST character-literal
     | DATABASE character-literal
     | USER character-literal
     | PASSWORD character-literal
     | SOCKET character-literal
     | OWNER character-literal

     | PORT numeric-literal }

출처 : http://m.blog.naver.com/kwoncharlie/10151416351


이제 Syntax를 이용하여 만들어 보자.

CREATE SERVER tlogin

FOREIGN DATA WRAPPER mysql

OPTIONS (

USER '접속ID',

PASSWORD '비밀번호',

HOST '접속DB IP',

PORT 3306, 

#SOCKET '/usr/local/mysql3/mysql.sock',

DATABASE 'DB명');


여기서 port는 반드시 integer 로 작성


이후 Federated 테이블 생성


CREATE TABLE `federated_server` (

  `nID` int(11) NOT NULL auto_increment,

  `PlayerID` varchar(36) NOT NULL default '',

  `Password` varchar(32) NOT NULL default '',

...

) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='tlogin/Player'

;


확인해 보쟈.


mysql > show create table fedrated_server\G



위와 같이 Connection 에서 tlogin/Player 으로 확인 가능하며, 정상적으로 select 도 될 수 있는 것을 확인할 수 있다.

보안적인 측면에서 효과를 볼 수 있다.




결론


이리 저리 DB에서 다른 원격지 DB의 정보를 가져 왔어 데이터를 쉽고, 프로그램 개발이 아닌 DB에서 해결하고자 하는 목적으로 진행을 해 보았다.

하지만 이 생각은 어디까지나 나의 욕심이고(DBA로써??아님 개발을 싫어하는 나로써??) 무식하면 용감하다고...

용감도 아닌 그냥 무식하고 무지해서 진행한 것이다.


여러 전문 DBA 고수분들은 비록 이런 기능이 있으나 사용하지 말라고 권고를 한다.

밑에 내용들만 조금만 깊게 생각해 보면 좋은 것 만은 아니라는 것을 알 수 있다.


1. 네트워크 성능에 따라 쿼리의 성능이 좌지우지.

2. 원격지의 Table에 DDL 작업이 발생 시 이것을 참조하는 Federated 테이블 에 대해서 재 생성

 - 혹시라도 federated 테이블을 모르는 경우 낭패..

3. 데이터 참조 시 해당 원격 DB 테이블을 모두 가져와야 하기에 처리량 증가 및 이에 따른 비용 증가


이 부분들은 여러 블로그를 조사하던 중에 참고한 내용을 기억나는 순으로 정리한 것이다.


가급적 사용하지 말자고 하는 것에서는 전부 이유가 있으니 가급적 사용안하는 방안으로 하고, 필요시 사용은 하되 엄격한 제한을 두고 사용하도록 해야겠다.


참조 : http://gywn.net/2014/12/let-me-introduce-federatedx/


반응형
반응형

Oracle 엔지니어겸 DBA 롤을 진행하다 보니 DB Link로 인해 종종 문제가 생긴 적이 많았다.


scn 이 Max치가 되어서 장애가 생긴적, 동일 DB 내에서 DB Link를 사용해서 불필요한 컨넥션 증가 등등...

어쩔때에는 db link 갯수가 한 DB내에 80개나 되는 경우도 있어서 당황한 적도 많았다.


그래서 DB Link만 생각해도 짜증나는 경우가 더 많았다.


하지만, MySQL DBA로 업무를 진행하다 보니 오히려 여기서는 DB Link 기능 없이 

Python 으로 일일이 개발해서 진행하는 경우가 허다하게 많았다.


처음부터 Python 개발을 했었다면 모르겠지만 Python을 익히면서 DBA 업무를 하다보니 괜히 개발이 더더더 싫어졌다.

(컴퓨터과에서 공부하며 DBA 가 되고 싶었지만 개발이 싫어서 DBA가 하고 싶은 부분도 상당히 많았기에...)


어쨋든 MySQL 에서도 Federated storage engine 이라는 것이 있어서 이 기술을 사용하면 db link 역활을 할 수 있다는 것을 찾아서 

이에 대해 간략한 설명과 테스트한 부분을 소개하고자 한다.



Federated Storage Engine 이란?


FEDERATED 스토리지 엔진을 사용하면 리플리케이션이나 클러스터 기술을 이용하지 않고도 원격의 MySQL 데이터베이스에 접근할 수 있다. 서비스 운영을 위해 여러 데이터베이스를 사용하는데, 한 데이터베이스의 데이터를 다른 데이터베이스들이 참조하여 사용할 때 활용할 수 있다. Oracle의 DBLink와 유사한 기능이라고 한다.


FEDERATED 엔진은 MySQL에 기본으로 설정되어 있지 않기 때문에 이를 사용하기 위해서는 별도의 작업이 필요하다. 검색을 해보면 처음에 설치할 때 부터 –with-federated-storage-engine 옵션을 주어야 한다는 등의 이야기 등이 있지만, 실제로는 재설치를 하거나 할 필요는 없다.

참조 : http://blog.weirdx.io/post/3503


그럼 나의 테스트 환경이다.

현재 회사 테스트 DB 장비와 나의 Local DB 를 연결하였다.


회사 테스트 DB는 5.0.37 이다



나의 local DB 는 5.7.12 이다

테스트는 개발장비의 데이터를 내 pc 에서 select 하고자 한다.


1. Engine 이 설치되어 있는지 확인해 본다. (Local DB)

 - 보통은 아래와 같이 Federated engine 이 NO 라고 되어 있는 것을 확인할 수 있다.



이 부분을 YES 로 변경해 보자.


my.cnf 또는 my.ini 파일에서 아래와 같이 추가해 보자


FEDERATED    만 추가한 후 저장하자.


(내 PC는 윈도우 이기에, my.ini 파일을 수정하였다.)



이 후, 적용을 위해서 DB를 재 기동 한다.


다시 Engine을 확인해 본다.




Federated가 YES 로 되어 있는 것을 확인 할 수 있다.


2. Engine을 이용하여 테이블을 추가해 보자.

 - Federated 엔진을 이용한 테이블은 쉽게 생각해 보면 원격 테이블을 가져와서 보여주는 것을 의미하며, 

   DML 작업을 진행하게 되면 원격지의 테이블 또한 변경이 되기에 굉장히 조심하자!!


* 원격지의 Table과 동일한 형태로 만들자

* 기본적으로 원격지 DB로 접속이 되는지 확인하자.(IP / Port 허용 여부)

* Oracle DB Link와 같이 원격지로 접근할 수 있도록 ID와 패스워드를 알아야 한다.


기본 문구는 아래와 같다.


CREATE TABLE `테이블명` (

  `컬럼1` 속성, 

  `컬럼2` 속성,

  `컬럼3` 속성

) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='mysql://원격지접속ID:패스워드@원격지DB의IP:포트/DB명/테이블명'

;


ex) 

CREATE TABLE `federated_table` (
  `nID` int(11) NOT NULL auto_increment,
  `PlayerID` varchar(36) NOT NULL default '',
  `Password` varchar(32) NOT NULL default '',
  `Name` varchar(20) NOT NULL default ''
) ENGINE=FEDERATED DEFAULT CHARSET=utf8 CONNECTION='mysql://root:password@192.168.1.70:3306/TestDB/Player'
;


3. 이렇게 추가가 정상적으로 되면 테스트 진행해 보자.


local 에서 federated_table 를 select 해 보자.



워낙 데이터가 많아 이렇게 먼저 비교를 해 보았다.


이번에는 데이터 한건에 대해서 DML 작업을 진행해 보자.



이 한건을 이용하여 Remote에서 지워지면 local 에서는 어떻게 되는지 보자.



지워져서 검색이 안되는 것을 확인할 수 있다.


다시 Insert를 진행해 보자.


local 에서 보여 지는 것을 확인할 수 있다.


이번에는 반대로 테스트 해 보자.

Local 에서 작업을 진행하면 원격지 DB에서는 어떻게 진행되는지 Delete 작업 하나만 해 보자.



Local 에서 삭제 작업을 진행 하였더니, 원격지에서 삭제 된 것을 확인할 수 있다.


DB Link를 대신 할 수 있는 분명 좋은 기능인 것을 확인할 수 있다.


이 작업을 통해서 파이썬을 이용한 작업을 대체할 수 있지 않을까 생각해 본다.

원격지의 필요한 것에 대해서 미리 테이블을 생성한 후 프로시저 등으로 작업을 진행하고, 스케줄러를 통해 주기적으로 한다면,

crontab 에 걸어서 사용을 하고 등의 필요성이 줄어들고, 동시에 보안도 해결되지 않을까 고민해 본다.



추가로 아래 사이트를 참조해도 좋을 듯 싶다.


http://blackbull.tistory.com/31


[HELP FEDERATED ENGINE]
길다.. 생략..... -0-;;;;;;;

[FEDERATED ENGINE 설명]
Federated Engine은,
실제적으로 물리적인 저장공간을 확보하여 데이터를 복사해서 갖는 것이 아니다.
무슨 말이냐 하면... 흠...

마치 C에서의 포인터나, C++, Java에서의 참조형 처럼,
단순히 틀에 대한 정보만을 지니고, 
그것을 원거리에서 MySQL의 API를 이용하여 접근하는 방식이다.


그리하여, 물리적으로 격리되어 있는 다른 MySQL 서버의 테이블로의 접근이 
로컬 내에서 가능하게 만들어준다.
(5.0 에서는 MySQL 서버간에만 사용가능하며, 추후에 이기종 DB 와의 연계도 개발할꺼라는데...
언제나 될런지 -0-;;;)

물론, 
DBLink와 마찬가지로 물리적 거리감은 실행 속도의 하락과
DDL(Data Definition Language) 같은 쿼리는 적용 되지 않는 부효과를 발생시킨다.

그런 이유로, 
만약 로컬에서 DROP TABLE 명령어를 사용하여 테이블을 DROP 시킨다면,
로컬만 DROP되고, 원거리의 TABLE에는 영향을 미치지 않는다.



[FEDERATED ENGINE 사용방법]
먼저, 원본 테이블이 어딘가 존재해야 한다.

# 원본 테이블
USE testdb;
CREATE TABLE testtbl (
 id INT AUTO_INCREMENT PRIMARY KEY,
 col1 VARCHAR(100) DEFAULT NULL,
 col2 VARCHAR(200) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=UTF8;


그리고 난 후에야, 로컬에 동일한 구조로 테이블을 생성한다.
단, 이번에는, 
****************************************************************************************
1. ENIGINE :  ENGINE=FEDERATED
2. CONNECTION 정보 : 'mysql://아이디:패스워드@IP또는DOMAIN:PORT/DB명/TABLE명'
****************************************************************************************

# FEDERATED 된 테이블
CREATE TABLE testtbl (
 id INT AUTO_INCREMENT PRIMARY KEY,
 col1 VARCHAR(100) DEFAULT NULL,
 col2 VARCHAR(200) DEFAULT NULL
) ENGINE=FEDERATED 
  DEFAULT CHARSET=UTF8
  CONNECTION='mysql://scott:tiger@192.168.10.2:3306/testdb/testtbl;


라고 만들면,
그 때부터 INSERT, DELETE, UPDATE, SELECT 가 가능해지며, 
INDEX를 사용할 수 있게 된다.

[FEDERATED 주의할 점]
1. 반드시 #원본테이블 처럼, 대상이 되는 테이블이 먼저 존재해야 한다.
2. Transaction은 지원되지 않는다.
3. #원본테이블 데이터를 제외한 필드명/타입/구조 등의 변경 사항은 
   #FEDERATED 된 테이블 적용이 되지 않기 때문에,
   수동으로 변경해 주어야 한다.
4. Query Cache는 이용할 수 없다.
5. !!!!! 중요 !!!!! SHOW CREATE TABLE #FEDERATED된 테이블
   입력시 #원본테이블로의 접속정보가 고스란히 노출 되므로, 주의가 요구된다.


반응형
반응형

[출처] http://blackbull.tistory.com/43

쿼리를 날리다 보면, 필요에 따라 그룹별로 순위를 매겨야 할 때가 있다.

이에 대해 오라클에서는 그러한 기능을 제공하는데,

아래가 바로 그 예이다.


[Oracle] 


SELECT empno, ename, job, sal, 

            ROW_NUMBER() OVER(PARTITION BY job ORDER BY sal) AS rnum 

FROM scott.emp;

<<결과>>

     EMPNO ENAME                JOB                       SAL       RNUM

---------- -------------------- ------------------ ---------- ----------

      7902 FORD                  ANALYST                    3000          1

      7788 SCOTT                ANALYST                   3000          2

      7369 SMITH                 CLERK                         800          1

      7900 JAMES                CLERK                         950          2

      7876 ADAMS                CLERK                       1100          3

      7934 MILLER                CLERK                       1300          4

      7782 CLARK                 MANAGER                  2450          1

      7698 BLAKE                 MANAGER                  2850          2

      7566 JONES                 MANAGER                  2975          3

      7839 KING                    PRESIDENT                5000          1

      7654 MARTIN               SALESMAN                 1250          1

      7521 WARD                  SALESMAN                 1250          2

      7844 TURNER               SALESMAN                 1500          3

      7499 ALLEN                 SALESMAN                 1600          4


14 개의 행이 선택되었습니다.




상기 쿼리는,

emp 테이블의 JOB을 기준으로 하여 그룹을 정하고 (PARTITION BY job),  -- 1

sal을 기준으로 하여 순위를 매겨(ORDER BY sal),

각각의 행에 ROW_NUMBER를 부여하겠다는 의미이다.                         -- 2


여기서 'PARTITION BY job'은 job별 정렬을 발생시킨다.

즉, 최종 결과물의 넘버링은 ORDER BY job, sal의 순으로 결과가 나오는 것이다.



[MySQL]

그런데, 불행하게도..... MySQL에는 저 기능이 없다.

그렇기 때문에 우리의 친구 꼼수(?)를 이용하여 저것을 구현해 내야 하는데.....


SELECT empno, ename, job, sal, rnum

FROM (

   SELECT a.*, 

           (CASE @vjob WHEN a.job THEN @rownum:=@rownum+1 ELSE @rownum:=1 END) rnum,

           (@vjob:=a.job) vjob

   FROM emp a, (SELECT @vjob:='', @rownum:=0 FROM DUAL) b

   ORDER BY a.job, a.sal                  

) c;

<<결과>>

+-------+--------+-----------+------+------+

| empno | ename  | job       | sal  | rnum |

+-------+--------+-----------+------+------+

|  7902 | FORD   | ANALYST   | 3000 |    1 |

|  7788 | SCOTT  | ANALYST   | 3000 |    2 |

|  7369 | SMITH  | CLERK     |  800 |    1 |

|  7900 | JAMES  | CLERK     |  950 |    2 |

|  7876 | ADAMS  | CLERK     | 1100 |    3 |

|  7934 | MILLER | CLERK     | 1300 |    4 |

|  7782 | CLARK  | MANAGER   | 2450 |    1 |

|  7698 | BLAKE  | MANAGER   | 2850 |    2 |

|  7566 | JONES  | MANAGER   | 2975 |    3 |

|  7839 | KING   | PRESIDENT | 5000 |    1 |

|  7654 | MARTIN | SALESMAN  | 1250 |    1 |

|  7521 | WARD   | SALESMAN  | 1250 |    2 |

|  7844 | TURNER | SALESMAN  | 1500 |    3 |

|  7499 | ALLEN  | SALESMAN  | 1600 |    4 |

+-------+--------+-----------+------+------+

14 rows in set (0.00 sec)


어때... 결과가 같아 보이는가? 


자, 그럼 쿼리를 뜯어보자.

여기서 궁금하게 생각되는 부분은 아래 3개의 쿼리라고 예상 된다.


1. (CASE @vjob WHEN a.job THEN @rownum:=@rownum+1 ELSE @rownum:=1 END) rnum,

--> 이전 job 필드와 동일한 그룹인가를 판별하고, 그룹에 따라 순번을 부여하기 위함이며,

      테이블에서 각각의 행을 읽을 때마다,

      변수 @vjob 값이 지금 새로 읽은 job 과 같다면 변수 @rownum을 1증가 시키고, 

      그렇지 않은 경우(@vjob이 현재 읽은 job값과 같지 않다면) @rownum을 1로 초기화 시킨다.


2. (@vjob:=a.job) as vjob

--> 테이블에서 각각의 행을 읽을 때마다,

      그룹 판별을 위해 현재 읽고 있는 행의 job값을 변수 @vjob에 입력


3. (SELECT @vjob:='', @rownum:=0 FROM DUAL) b

--> 원래는 쿼리를 수행하기 이전에, 

      SET @vjob:=0, @rownum:=0;  을 수행하여 변수를 초기화 해야 한다. 

      만약 해주지 않으면, NULL 값이 들어가게 된다.


      하지만 그럴 경우 쿼리가 2번 수행되어야 하기 때문에,

      하나의 쿼리로 만들기 위해서 이런 식의 서브 쿼리를 이용한 것이다.

      이 서브쿼리는 초기 테이블 확인시 1회만 수행되고,

      이후부터는 열람되지 않는다.

    

      !! 주의 !! 

      서브쿼리 안에서의 결과값만 가지고 현재의 결과값을 얻고자 할 때,

      변수가 되는 항목의 값을 동일한 자료형으로 맞춰주지 않으면, 

      정상적인 결과값이 나오지 않는다.

      가령 위의 예를 이용하자면, @vjob의 초기값을 @vjob:=0 으로 수행 하고

      서브쿼리만을 수행하면 정상적인 결과값이 나오지 않게 된다. 

      한 번 해보자~

       

이 3가지를 이해한다면 아마 이해할 수 있을 것이라 생각되지만,

한 가지 짚고 넘어가야 할 것이 있다. 


Q. 우리가 흔히 쓰는 SELECT 문장의 수행순서는 어떻게 될까?

무슨의미냐 하면..

위에서 사용한 것처럼 변수를 이용한 SELECT 내 연속적인 값의 할당은, 

수행결과에 영향을 미치게 되지 않을까? 

라는 질문이다.


흠.. 내가 말을 써놓고 난해하군..

예제를 보도록 하자.


<<예제>>

SET @val1=0, @val2=0;    #아까도 말했듯이 변수 초기화는 먼저 선행되어야 한다.

SELECT @val1:=@val1+1, @val2:=@val1+1, @val2:=0, @val1=@val2+1 

FROM DUAL;


자.... 당신이 예상하는 결과는?.....




<<쿼리 수행 결과>>

 +----------------+----------------+----------+---------------+

| @val1:=@val1+1 | @val2:=@val1+1 | @val2:=0 | @val1=@val2+1 |

+----------------+----------------+----------+---------------+

|                      1 |                     2 |             0 |                    1 |

+----------------+----------------+----------+---------------+

1 row in set (0.00 sec)


상기와 같이 SELECT 내 수행 결과는,

왼쪽에서 오른쪽으로 순차적인 수행이 이루어짐을 알 수 있다.


즉, @val1:=@val1+1 → @val2:=@val1+1 → @val2:=0  →  @val1=@val2+1 

로 수행 순서가 정해진다는 의미.


그러므로, 

변수를 이용한 SELECT를 이용할 때는 반드시 수행순서를 염두해 두고 쿼리를 작성하도록 하자.




PS : 오라클에는 예제 테이블이 있지만 MySQL 에는 없으니

       혹시 테스트 해보고 싶은 사람은 아래 쿼리를 수행해서 테스트 해보도록...


CREATE TABLE emp (

   empno INT,

   ename VARCHAR(30),

   job VARCHAR(30),

   sal INT

)ENGINE=INNODB DEFAULT CHAR SET=UTF8;


INSERT INTO emp

VALUES

(7902,'FORD','ANALYST',3000),

(7788,'SCOTT','ANALYST',3000),

(7369,'SMITH','CLERK',800),

(7900,'JAMES','CLERK',950),

(7876,'ADAMS','CLERK',1100),

(7934,'MILLER','CLERK',1300),

(7782,'CLARK','MANAGER',2450),

(7698,'BLAKE','MANAGER',2850),

(7566,'JONES','MANAGER',2975),

(7839,'KING','PRESIDENT',5000),

(7654,'MARTIN','SALESMAN',1250),

(7521,'WARD','SALESMAN',1250),

(7844,'TURNER','SALESMAN',1500),

(7499,'ALLEN','SALESMAN',1600);


반응형
반응형

공부하다가 오라클의 Trace 의 개념으로 예상되는 부분을 찾았다.

show engine innodb status

 -> InnoDB 에 대한 현재 상태를 확인할 수 있는 명령어

  • Semaphores
  • Transactions
  • File I/O
  • Insert Buffer and Adaptive Hash Index
  • Buffer pool and memory
  • Row operations
  • Lastest Detected deadlock
    • Deadlock 발생 시 해당 항목 확인
    • Transaction 정보를 표시
    • Waiting for this lock to be Granted (트랜잭션이 실행하기 위해 lock 을 걸어야 하는 데이터에 대한 정보, row에 대한 정보를 표시
    • Holds the lock(s) (현재 잡고있는 lock 의 정보)
  • Lastest Foreign key error

이론도 중요하지만 당장 테스트 해 보았다.


2개의 Session 에 대해서 lock 을 걸어 보았다.


※ MySQL 5.7 InnoDB on Windows 이며, 전부 Default 로 설정 하였다.

 

Lock 을 발생하기 위해서는 autocommit 을 반드시 off 인지 확인해 보자


mysql> show variables like '%commit%';

+-----------------------------------------+-------+

| Variable_name                           | Value |

+-----------------------------------------+-------+

| autocommit                              | OFF   |

| binlog_group_commit_sync_delay          | 0     |

| binlog_group_commit_sync_no_delay_count | 0     |

| binlog_order_commits                    | ON    |

| innodb_api_bk_commit_interval           | 5     |

| innodb_commit_concurrency               | 0     |

| innodb_flush_log_at_trx_commit          | 1     |

| slave_preserve_commit_order             | OFF   |

+-----------------------------------------+-------+

8 rows in set, 1 warning (0.00 sec)


양쪽 session 에서 동일한 데이터에 update 를 하여 Lock 을 발생 후 확인해 보자


1번 session

mysql> update test1 set txt='4' where id =1;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1  Changed: 1  Warnings: 0


mysql> select * from employees.test1;

+----+-----+

| id | txt |

+----+-----+

|  1 | 4   |

|  2 | 2   |

|  3 | 3   |

|  5 | 5   |

|  6 | 7   |

+----+-----+

5 rows in set (0.00 sec)



2번 session

mysql> select * from test1;

+----+-----+

| id | txt |

+----+-----+

|  1 | 1   |

|  2 | 2   |

|  3 | 3   |

|  5 | 5   |

|  6 | 7   |

+----+-----+

5 rows in set (0.00 sec)


mysql> update test1 set txt='3' where id=1;

mysql> show engine innodb status \G;

*************************** 1. row ***************************

  Type: InnoDB

  Name:

Status:

=====================================

2016-06-02 15:41:56 0x2b84 INNODB MONITOR OUTPUT

=====================================

Per second averages calculated from the last 24 seconds

-----------------

BACKGROUND THREAD

-----------------

srv_master_thread loops: 2 srv_active, 0 srv_shutdown, 421 srv_idle

srv_master_thread log flush and writes: 423

----------

SEMAPHORES

----------

OS WAIT ARRAY INFO: reservation count 15

OS WAIT ARRAY INFO: signal count 14

RW-shared spins 0, rounds 54, OS waits 5

RW-excl spins 0, rounds 0, OS waits 0

RW-sx spins 0, rounds 0, OS waits 0

Spin rounds per wait: 54.00 RW-shared, 0.00 RW-excl, 0.00 RW-sx

------------

TRANSACTIONS

------------

Trx id counter 17161

Purge done for trx's n:o < 16713 undo n:o < 0 state: running but idle

History list length 60

LIST OF TRANSACTIONS FOR EACH SESSION:

---TRANSACTION 17160, ACTIVE 32 sec starting index read

mysql tables in use 1, locked 1

LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)

MySQL thread id 2, OS thread handle 11152, query id 23 localhost ::1 root updating

update test1 set txt='3' where id=1

------- TRX HAS BEEN WAITING 32 SEC FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 80 page no 3 n bits 72 index PRIMARY of table `employees`.`test1` trx id 17160 lock_mode X locks rec but not gap waiting

Record lock, heap no 2 PHYSICAL RECORD: n_fields 4; compact format; info bits 0

 0: len 4; hex 80000001; asc     ;;

 1: len 6; hex 000000004307; asc     C ;;

 2: len 7; hex 270000022302e9; asc '   #  ;;

 3: len 1; hex 34; asc 4;;


------------------

---TRANSACTION 17159, ACTIVE 94 sec

2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1

MySQL thread id 3, OS thread handle 11140, query id 24 localhost ::1 root starting

show engine innodb status

Trx read view will not see trx with id >= 17159, sees < 17159

--------

FILE I/O

--------

I/O thread 0 state: wait Windows aio (insert buffer thread)

I/O thread 1 state: wait Windows aio (log thread)

I/O thread 2 state: wait Windows aio (read thread)

I/O thread 3 state: wait Windows aio (read thread)

I/O thread 4 state: wait Windows aio (read thread)

I/O thread 5 state: wait Windows aio (read thread)

I/O thread 6 state: wait Windows aio (write thread)

I/O thread 7 state: wait Windows aio (write thread)

I/O thread 8 state: wait Windows aio (write thread)

I/O thread 9 state: wait Windows aio (write thread)

Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,

 ibuf aio reads:, log i/o's:, sync i/o's:

Pending flushes (fsync) log: 0; buffer pool: 0

507 OS file reads, 64 OS file writes, 15 OS fsyncs

0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s

-------------------------------------

INSERT BUFFER AND ADAPTIVE HASH INDEX

-------------------------------------

Ibuf: size 1, free list len 0, seg size 2, 0 merges

merged operations:

 insert 0, delete mark 0, delete 0

discarded operations:

 insert 0, delete mark 0, delete 0

Hash table size 34679, node heap has 0 buffer(s)

Hash table size 34679, node heap has 0 buffer(s)

Hash table size 34679, node heap has 0 buffer(s)

Hash table size 34679, node heap has 0 buffer(s)

Hash table size 34679, node heap has 0 buffer(s)

Hash table size 34679, node heap has 0 buffer(s)

Hash table size 34679, node heap has 0 buffer(s)

Hash table size 34679, node heap has 0 buffer(s)

0.00 hash searches/s, 0.00 non-hash searches/s

---

LOG

---

Log sequence number 345901173

Log flushed up to   345901173

Pages flushed up to 345901173

Last checkpoint at  345901164

0 pending log flushes, 0 pending chkp writes

15 log i/o's done, 0.00 log i/o's/second

----------------------

BUFFER POOL AND MEMORY

----------------------

Total large memory allocated 137297920

Dictionary memory allocated 673260

Buffer pool size   8192

Free buffers       7678

Database pages     514

Old database pages 209

Modified db pages  0

Pending reads      0

Pending writes: LRU 0, flush list 0, single page 0

Pages made young 0, not young 0

0.00 youngs/s, 0.00 non-youngs/s

Pages read 479, created 35, written 41

0.00 reads/s, 0.00 creates/s, 0.00 writes/s

Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000

Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s

LRU len: 514, unzip_LRU len: 0

I/O sum[0]:cur[0], unzip sum[0]:cur[0]

--------------

ROW OPERATIONS

--------------

0 queries inside InnoDB, 0 queries in queue

1 read views open inside InnoDB

Process ID=4620, Main thread ID=10324, state: sleeping

Number of rows inserted 2, updated 1, deleted 0, read 26

0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s

----------------------------

END OF INNODB MONITOR OUTPUT

============================


1 row in set (0.00 sec)


ERROR:

No query specified



이렇게 Lock 이 발생한 것을 확인 할 수 있고, 어떤 쿼리가 Lock 이 걸려 있는지 확인이 가능하다.


해당 쿼리에 대한 해석은 제대로 해야 될 듯 싶다.

그러면 튜닝 또는 장애 발생 시 정확한 원일을 알 수 있는 척도가 될 듯 싶다.


mysql> show engine innodb status \G;



[출처] http://dba-jadelee.blogspot.kr/2014/10/mysql-innodb-status-monitoring.html

MySQL INNODB Status Monitoring

-  해당 STATUS출력내역은 각 상세내역 설명을 위해 특정장비를 기준으로 특정시점의 결과를 샘플링  

세부적으로 설명한 부분도 있지만 직관적으로 상태정보를 보여주는 부분은 상세한 설명은 생략함. (이 부분들에 대한 추가적인 질문은 개인별로 문의하세요)

각 부분에 대한 간략한 기능적 설명이며 모니터링상 중요한 영역에 대한 코멘터리는 각 영역에 대한 설명 마지막 부분에 기재하였음.

-----------------------------------------------------------------


SQL> SHOW ENGINE INNODB STATUS\G


=====================================
131129 12:58:12 INNODB MONITOR OUTPUT      <--- 분석시점에 대한 출력시간
=====================================
Per second averages calculated from the last 30 seconds   <--- 분석에 대한 대상시간범위 (출력시간으로부터 *초 전까지의 범위)


----------------------------
BACKGROUND THREAD      
----------------------------               
InnoDB 메인 백그라운드 스레드의 작업실행 통계 각 숫자는 Innodb Engine이 시작된 이후부터의 카운트 값

srv_master_thread loops: 18613866 1_second, 18613864 sleeps, 1861347 10_second, 1755 background, 1739 flush
<--- 순서대로 초당 루프횟수 / 초당 슬립횟수 / 10초당 루프횟수 / User Transaction이 없는 유휴시간대 백그라운드 연산의 루프횟수플러시 루프횟수를 의미

srv_master_thread log flush and writes: 18683584
<--- 로그 메시지를 기록하고 플러시한 횟수를 의미 (Redo + Undo)


-----------------
SEMAPHORES              
-----------------          
InnoDB 내부 세마포어(뮤텍스나 리드/라이트 락 세마포어를 기다리는 스레드에 대한 정보)  통계 : 각 숫자는 Innodb Engine이 시작된 이후부터의 카운트 값이며 각 카운트 값이 갑자기 높은 시간대에 대해서는 DISK I/O 성능 및 InnoDB 엔진경합을 의심

OS WAIT ARRAY INFO: reservation count 1206724952, signal count 3304987791
<--- 전역 대기 배열정보 : 배열이 생성된 후에 셀을 예약한 횟수 / 객체가 시그널을 받은 횟수를 의미

Mutex spin waits 39567225498, rounds 173270862365, OS waits 330572230
<--- 뮤텍스 대기 스핀정보 : 뮤텍스를 기다리는 스핀락의 호출횟수 / 스핀루프의 반복횟수 / OS의 호출을 기다린 횟수를 의미

RW-shared spins 2945944901, rounds 37722913141, OS waits 601963335
<--- 공유 리드락 스핀정보 : 공유 리드락이 걸린 시간동안 스핀락이 기다린 횟수 / 스핀루프의 반복횟수 / OS의 호출을 기다린 횟수를 의미                       

RW-excl spins 684786004, rounds 12265810889, OS waits 163680647
<--- 배타적 라이트락 스핀정보 : 배타적 라이트락이 걸린 시간동안 스핀락이 기다린 횟수 / 스핀루프의 반복횟수 / OS의 호출을 기다린 횟수를 의미

Spin rounds per wait: 4.38 mutex, 12.81 RW-shared, 17.91 RW-excl
<--- 각 뮤텍스에 대해 OS의 호출을 기다리며 스핀루프가 기다린 횟수를 의미


------------------------------------
LATEST FOREIGN KEY ERROR 
------------------------------------            
최근 발생한 트랜잭션별 참조키 에러내역 히스토리 : 제약조건에 위배되는 내역에 대한 트랜잭션 및 쿼리 정보 확인

세부 에러 내역은 생략


------------------------------------
LATEST DETECTED DEADLOCK
------------------------------------           
최근 발생한 트랜잭션별 데드락내역 히스토리 : 가장 최근 발생한 트랜잭션간 데드락 이슈에 대한 처리내역 확인 (경합된 트랜잭션간의 내역 및 데드락 해결을 위한 트랜잭션 처리내역)

세부 데드락 내역은 생략


-------------------
TRANSACTIONS  
-------------------           
현재 트랜잭션별 락모니터링 정보 : 실제 수행되고 있는 트랜잭션별 작업내역에 대한 락 핸들링 정보 및 락 사용 세부쿼리 내역을 확인

세부 트랜잭션 내역은 생략


----------
FILE I/O    
----------         
다양한 I/O 연산에 대한 Innodb 스레드 실행내역 및 통계 : 내부적인 I/O 스레드의 현재 상태 및 전체 통계값 제공하며 만약 I/O상의 부하나 상태이상이 의심될 때 참조될 수 있음.

I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (read thread)
I/O thread 4 state: waiting for i/o request (read thread)
I/O thread 5 state: waiting for i/o request (read thread)
I/O thread 6 state: waiting for i/o request (write thread)
I/O thread 7 state: waiting for i/o request (write thread)
I/O thread 8 state: waiting for i/o request (write thread)
I/O thread 9 state: waiting for i/o request (write thread)
---> 현재 Innodb엔진이 사용중인 I/O 스레드들의 현재 상태 (각 스레드의 역할에 대한 명칭은 각 줄 끝 괄호내역 확인)

Pending normal aio reads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
---> 대기하는 연산에 대한 정보  (aio 는 비동기 입출력을 의미)

21113936456 OS file reads, 7012874230 OS file writes, 5248276317 OS fsyncs
---> Innodb 엔진이 시작된 이후 전체통계 카운트

670.33 reads/s, 16384 avg bytes/read, 387.61 writes/s, 196.80 fsyncs/s
---> 마지막으로 통계를 출력한 이후의 전체통계 값에 대한 초단위 처리 카운트


------------------------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX      
------------------------------------------------------        
인서트 버퍼와 적응형 해시에 대한 정보 : 버퍼와 해시의 효율에 대한 통계정보 확인

Ibuf: size 38747, free list len 48247, seg size 86995, 183927359 merges
---> 페이지에 있는 삽입버퍼의 인덱스트리 사이즈 / 사용가능한 프리리스트의 길이 / 삽입버퍼트리와 헤더를 갖고 있는 파일에 할당된 페이지수 / 합병된 페이지수 를 의미

merged operations:
 insert 1037160756, delete mark 902047899, delete 260585507
---> 인덱스 페이지에 합병한 각 DML연산의 횟수를 의미

discarded operations:
 insert 110253, delete mark 5399, delete 2043
---> 테이블스페이스나 인덱스가 삭제되어 합병하지 않고 버려진 각 DML연산의 횟수를 의미

Hash table size 4425293, node heap has 1037 buffer(s)
---> 적응형 해시 인덱스 테이블에 있는 셀의 개수와 예약된 버퍼프레임의 개수를 의미

1057.94 hash searches/s, 1352.65 non-hash searches/s
---> 검색한 적응형 해시 인덱스 검색에 성공한 횟수 / 적응형 해시 인덱스를 사용할 수 없을때 B-tree 인덱스를 검색한 횟수를 의미


-------
LOG
-------
Innodb Log 활동에 대한 통계

Log sequence number 7804454235313     
---> 현재 로그 일련번호 (lsn)

Log flushed up to   7804454234099
---> 로그파일에서 플러시된 항목의 개수

Last checkpoint at  7804369829116
---> 가장 최근의 체크포인트된 lsn 정보

0 pending log writes, 0 pending chkp writes
4882215617 log i/o's done, 153.85 log i/o's/second

log switch 이슈와 관련
VIEW POINT : (Log flushed up to - Last checkpoint at) 값은 체크포인트가 얼마나 오래되었는지를 확인할 수 있음.
체크 포인트값이 (innodb_log_file_size * innodb_log_files_in_group) 77% 이상이 되지 않게 모니터링하고 유지되어야 함. (권장된 모니터링수치)
만약 이 비율에 가깝거나 큰 비율 값이 나온다면 Innodb엔진은 공격적으로 플러싱을 시도하게 되며 이로 인한 DB연산이 멈출 수 있음.


------------------------------------
BUFFER POOL AND MEMORY
------------------------------------            
Innodb 버퍼풀과 메모리 사용량에 대한 통계정보 : Innodb 버퍼에 대한 LRU 관리방법에 의한 할당내역 및 사용내역(byte단위)  버퍼사용율에 대한 세부통계수치 확인

Total memory allocated 2197815296; in additional pool allocated 0
---> 버퍼로 할당된 메모리 전체사이즈 / 추가풀에 할당된 메모리사이즈를 의미

Dictionary memory allocated 8409400
---> 데이터딕셔너리 테이블과 인덱스에 할당된 메모리사이즈를 의미

Buffer pool size   131072
Free buffers       21
---> 버퍼풀 사이즈를 페이지 단위로 알려주고 / 버퍼풀에 있는 해재된(free) 버퍼의 개수를 의미 : 프리버퍼가 없는 경우가 잦으면 버퍼사이즈를 늘려주는 것을 권장.

Database pages     130014
Old database pages 47973
Modified db pages  5660
---> 버퍼의 현재 LRU큐의 길이 / 과거 LRU큐의 길이 / 플러시해야할 페이지의 개수를 의미 : 기본적으로 Innodb는 버퍼풀을 LRU로 관리하며 할당과 해제에 대해서 페이지단위로 관리됨.

Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
---> 대기하고 있는 읽기연산의 개수 / LRU 관리방식에 따른 플러시하기 위해 대기하고 있는 페이지의 개수 / Buf_flush_list에서 플러시하기위해 기다리고 있는 페이지의 개수 / Buf_flush_single_page 리스트에서 플러시하기 위해 기다리고 있는 페이지의 개수를 의미

Pages made young 47722254403, not young 0
3258.74 youngs/s, 0.00 non-youngs/s
---> 최근에 접근한 페이지의 개수 / 최근에 접근하지 않은 페이지의 개수를 의미

Pages read 25295158134, created 95903681, written 2392506665
670.33 reads/s, 2.00 creates/s, 235.76 writes/s
---> 페이지의 읽기 연산 카운트 버퍼풀에 생성했지만 읽지않은 페이지의 개수 / 쓰기 연산 카운트를 의미

Buffer pool hit rate 997 / 1000, young-making rate 19 / 1000 not 0 / 1000
---> 획득한 버퍼풀 페이지 수와 비교하여 읽은 페이지 수의 비율 / 획득한 버퍼풀 페이지 수와 비교 및 접근한 페이지 수의 비율 / 획득한 버퍼풀 페이지 수와 비교 및 접근하지 않은 페이지 수의 비율을 의미

Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
---> 미리 읽기 비율 / 접근하지 않아서 제거된 미리 읽기 페이지수의 비율 / 랜덤 미리 읽기 비율

LRU len: 130014, unzip_LRU len: 0
I/O sum[108645]:cur[907], unzip sum[0]:cur[0]


----------------------
ROW OPERATIONS
----------------------
메인 스레드의 행 연산에 대한 통계 정보

2 queries inside InnoDB, 0 queries in queue
5 read views open inside InnoDB
---> 현재 실행중인 쿼리 / innodb_thread_concurrency 큐에 있는 쿼리의 개수 / 읽은 뷰의 개수를 의미

Main thread process no. 16530, id 140226923562752, state: sleeping
---> 메인 스레드의 ID 및 상태정보를 의미 (첫번째 no. OS의 프로세스ID)

Number of rows inserted 3941662945, updated 2611269253, deleted 1052306048, read 11030869627676
39.96 inserts/s, 57.94 updates/s, 2.00 deletes/s, 908015.98 reads/s
---> innodb 엔진 시작된 이후의 각 DML연산의 총합계 카운트 / 초당 각 DML연산의 횟수 카운트를 의미

--------------------------------------------------------
END OF INNODB MONITOR OUTPUT

========================================================


[출처] http://intomysql.blogspot.kr/2010/12/innodb-lock.html

  • 우선 각 트랜잭션은 “TRANSACTION 999999 999999”으로 시작된다. (TRANSACTION ID는 8바이트 숫자 값인데, 이러한 형태의 8바이트 숫자 값은 모두 상위 4바이트와 하위 4바이트 두 영역으로 나뉘어서 출력된다.)
  • 그러므로, 여기 예제에서는 현재 3개의 트랜잭션 (09번 라인, 13번 라인, 23번 라인)이 존재한다는 것을 확인할 수 있다.
  • 각 TRANSACTION 라인에는 현재 해당 트랜잭션이 어떤 작업을 하고 있는지 어떤 상태인지를 알려 주는 키워드가 표시되며, 해당 트랜잭션이 몇 초 동안 진행 중인지도 보여 준다.- 09번 라인 : not started è 현재 트랜잭션이 진행 중이지 않음을 의미- 13번 라인 : ACTIVE è 현재 트랜잭션이 4초 동안 활성화된 상태임 (경우에 따라 문장 끝에 어떤 작업 중인지를 표시해 줌 : starting index read)- 23번 라인 : ACTIVE è 현재 트랜잭션이 17251초 동안 활성화된 상태임
  • 각각의 트랜잭션들은 “MySQL thread id”라는 항목(10, 16, 24번 라인)을 가지는데, 이 thread id값은 MySQL에서 “SHOW PROCESSLIST” 명령의 결과에 보여지는 “id”와 동일한 값을 가지게 된다. 즉, 현재 트랜잭션 목록에서 제일 밑 트랜잭션 (TRANSACTION 0 1809458)을 종료하고자 하면, “kill 4”명령으로 트랜잭션을 종료시킬 수 있다.
  • 13번 라인의 트랜잭션은 “TRX HAS BEEN WAITING 4 SEC FOR THIS LOCK TO BE GRANTED:”이라는 항목을 가지고 있는데, 이는 현재 트랜잭션 (TRANSACTION 0 1809460)이 다른 트랜잭션이 이미 점유한 Lock 때문에 Blocking(대기) 상태임을 표시하며, 어떤 Lock을 기다리고 있는지 상세히 보여 준다. 하지만, 안타깝게도 이 결과로는 어떤 트랜잭션이 그 Lock을 가지고 있는지는 알아낼 수 없다. 대략 짐작해 보건데 그 밑에 있는 트랜잭션이 지금 17251초 동안 트랜잭션이 ACTIVE 상태인 것으로 보아서 문제를 유발하고 있을 것이라는 것 정도는 짐작해 볼 수 있게 된다. 조금 더 자세히 확인하기 위해서는 “innodb_lock_monitor” 가 필요한데, 이 내용은 하단의 “InnoDB Lock monitoring” 을 참조 바란다.
  • 19번 라인을 보면, 레코드 Lock에 관련된 정보가 나오는데, 이것은 현재 트랜잭션이 대기 중인 레코드(인덱스)를 의미하며, 그 인덱스의 정보를 20, 21번 라인에 걸쳐서 보여 주고 있다. 19번 라인에는 지금 대기하고 있는 Lock이 Shared-lock인지 Exclusive-lock인지를 그리고 Gap까지 잠그고 있는지 아닌지를 보여 준다. 일반적으로 Gap lock이 아니라고 표현되는 경우를 제외하고는 거의 모두 Gap까지 잠그고 있다고 생각하면 될 듯 하다. (Gap을 잠그고 있는지 아닌지 판단하는 또 다른 방법은 “undo entries” 항목의 수가 “row lock(s)”의 수보다 작으면 대부분 Gap lock 으로 판단할 수 있다. 하지만 이 방법도 정확한 것은 아니다. 예를 들어서 한 트랜잭션에서 하나의 레코드만 계속 업데이트하게 되면 undo entries가 row locks보다 커질 수 있기 때문이다.)
  • 21번 라인을 보면, 드디어 이해 불가능의 단어들이 출력되는데, 사실 이 부분이 의외로 문제 해결에 도움이 될 수 있다. 우선 이 라인에 표시되는 내용은 인덱스 레코드의 필드 값들을 출력해서 보여 주는데, HEX값과 ASCII값을 동시에 보여 준다. 21번 라인의 내용을 정리해 보면 아래와 같이 잘라서 생각해 볼 수 있다. (구분자는 ;; 임)- 0: len 1; hex 70; asc p;;- 1: len 1; hex 02; asc  ;;- 2: len 4; hex 00000009; asc     ;;- 3: len 4; hex 00000000; asc     ;;각 라인은 [인덱스상에서의 번호 : 필드 길이 : 16진수 필드 값(HEX) : ASCII 필드 값(ASC) ] 포맷으로 구성되어 있다. 그리고 이 필드들의 개수는 20번 라인의 n_fields와 동일한 값을 가지게 된다.이 값들과 19번 라인의 테이블 및 인덱스 명을 이용하면 어느 테이블의 어떤 레코드를 지금 기다리고 있는지를 알아낼 수 있다.
  • "SHOW ENGINE INNODB STATUS"의 "DEADLOCK" 섹션에 출력되는 내용도 지금까지의 설명한 내용과 동일한 패턴으로 출력되므로, DEADLOCK 정보를 확인할 때에도 이와 같은 방식으로 해석할 수 있다.

지금까지 간단히 트랜잭션의 내용을 읽는 방법을 확인해 보았다.


InnoDB Lock monitoring
우선 InnoDB의 Lock을 모니터링 하기 위해서는 아래와 같은 테이블을 생성해야 한다.

Create table innodb_lock_monitor (fd1 int) engine=innodb;

  • 이 테이블을 생성하면, 매 몇 초 단위로 SHOW ENGINE INNODB STATUS 결과를 MySQL 에러 로그 파일에 기록하므로 모니터링이완료되면 테이블을 삭제 해주는 것이 좋다.
  • 위의 테이블을 생성 후, “SHOW ENGINE INNODB STATUS” 명령을 실행하면 아래와 같은 좀 더 상세한 트랜잭션 정보를 확인할 수 있다.
  • 어떤 트랜잭션이 다른 트랜잭션의 처리를 Blocking(막고) 하고 있는지를 판단하기 위해서는, 각 트랜잭션에서 가지고 있거나 또는 기다리고 있는 테이블 및 인덱스 그리고 그 인덱스 페이지 번호로 추적해 볼 수 있다. (물론 이 방법도 정확하게 찾을 수 있는 방법은 아니다. 하지만 더 자세히는 지금의 InnoDB 에서는 무리일지도 모른다)
  • 아래 빨간색으로 표기된 부분을 비교해 봄으로써 두 개의 트랜잭션이 서로 Racing 상태임을 확인할 수 있다. (동일 테이블의 동일 인덱스에서 같은 인덱스 페이지 번호 4를 참조하고 있음)

------------
TRANSACTIONS
------------
01 Trx id counter 0 1809465
02 Purge done for trx's n:o < 0 1809462 undo n:o < 0 0
03 History list length 22
04 LIST OF TRANSACTIONS FOR EACH SESSION:
05 ---TRANSACTION 0 0, not started, process no 5975, OS thread id 1099274560
06 MySQL thread id 10, query id 442 localhost root
07 show engine innodb status
08
09
10 ---TRANSACTION 0 1809464, ACTIVE 12 sec, process no 5975, OS thread id 1281038656 starting index read
11 mysql tables in use 1, locked 1
12 LOCK WAIT 2 lock struct(s), heap size 368, 1 row lock(s)
13 MySQL thread id 9, query id 400 localhost root Updating
14 update article set article_title='xx' where article_category=112 and article_type='general'
15 ------- TRX HAS BEEN WAITING 12 SEC FOR THIS LOCK TO BE GRANTED:
16 RECORD LOCKS space id 88 page no 4 n bits 88 index ix_category_type_id_user of table test.article trx id 0 1809464 lock_mode X locks rec but not gap waiting
17 Record lock, heap no 10 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
18  0: len 1; hex 70; asc p;; 1: len 1; hex 02; asc  ;; 2: len 4; hex 00000009; asc     ;; 3: len 4; hex 00000000; asc     ;;
19
20 TABLE LOCK table test.article trx id 0 1809464 lock mode IX
21 RECORD LOCKS space id 88 page no 4 n bits 88 index ix_category_type_id_user of table test.article trx id 0 1809464 lock_mode X locks rec but not gap waiting
22 Record lock, heap no 10 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
23  0: len 1; hex 70; asc p;; 1: len 1; hex 02; asc  ;; 2: len 4; hex 00000009; asc     ;; 3: len 4; hex 00000000; asc     ;;
24
25
26 ---TRANSACTION 0 1809463, ACTIVE 21 sec, process no 5975, OS thread id 1099008320
27 3 lock struct(s), heap size 368, 2 row lock(s), undo log entries 1
28 MySQL thread id 8, query id 355 localhost root
29 TABLE LOCK table test.article trx id 0 1809463 lock mode IX
20 RECORD LOCKS space id 88 page no 4 n bits 88 index ix_category_type_id_user of table test.article trx id 0 1809463 lock_mode X locks rec but not gap
21 Record lock, heap no 10 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
22  0: len 1; hex 70; asc p;; 1: len 1; hex 02; asc  ;; 2: len 4; hex 00000009; asc     ;; 3: len 4; hex 00000000; asc     ;;
23
24 RECORD LOCKS space id 88 page no 6 n bits 80 index PRIMARY of table test.article trx id 0 1809463 lock_mode X locks rec but not gap
25 Record lock, heap no 11 PHYSICAL RECORD: n_fields 10; compact format; info bits 0

26  0: len 4; hex 00000009; asc     ;; 1: len 6; hex 0000001b9c37; asc      7;; 2: len 7; hex 000000002d1f51; asc     - Q;; 3: len 1; hex 70; asc p;; 4: len 2; hex 7878; asc xx;; 5: len 30; hex 3c703e3c7370616e207374796c653d22666f6e742d73697a653a20313470; asc

반응형
반응형

조언으로 항상 체크해 봐야겠다.

[출처] https://blog.lael.be/post/370#comments

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

권장사항이다. 이것을 이해하면 당신의 어플리케이션이 더 나은 성능을 발휘할 것이다.

다만 이것이 사람의 실력을 판단하는 척도로 사용되서는 안 될 것이다.

 

작게 생각하기

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

 

EXPLAIN 안 써보기

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

 

잘못된 데이터 타입 선택

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

 

PHP에서 pconnect 쓰는 짓

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

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

 

스토리지 엔진 이해 못 하는 것

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

 

인덱스 레이아웃 이해 못 하는 것

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

 

쿼리 캐시 이해 못 하는 것

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

 

Stored Procedure를 쓰는 것

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

 

인덱스 컬럼에 함수 쓰는 것

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

 

인덱스 빼먹거나 쓸모없는 인덱스 만들어 놓는 것

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

 

join 안 쓰는 짓

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

 

Deep Scan 고려하지 않는 것

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

 

InnoDB 테이블에서 WHERE 조건절 없이 SELECT COUNT(*) 하는 짓

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

 

프로파일링이나 벤치마킹 안 하는 것

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

 

AUTO_INCREMENT 안 쓰는 것

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

 

ON DUPLICATE KEY UPDATE를 안 쓰는 것

- 레코드가 있으면 업데이트하고 없으면 인서트하고 이런 코드 필요없다!! 다 날려버려라!!
- 서버에 불필요하게 왔다갔다 할 필요가 없어짐
- 5-6% 정도 빠름
- 데이터 입력이 많다면 더 커질 수 있음
하지 말아야 할 것 총정리
Thinking too small
Not using EXPLAIN
Choosing the wrong data types
Using persistent connections in PHP
Using a heavy DB abstraction layer
Not understanding storage engines
Not understanding index layouts
Not understanding how the query cache works
Using stored procedures improperly
Operating on an indexed column with a function
Having missing or useless indexes
Not being a join-fu master
Not accounting for deep scans
Doing SELECT COUNT(*) without WHERE on an InnoDB table
Not profiling or benchmarking
Not using AUTO_INCREMENT
Not using ON DUPLICATE KEY UPDATEK

반응형
반응형

출처 : https://mariadb.com/kb/ko/mariadb-mysql/#mariadb와-mysql-proxy의-비호환성

MariaDB는 MySQL을 즉시 교체할 수 있는 바이너리이다

모든 실용적인 목적에서 MariaDB는 동일한 MySQL 버전을 즉시 교체할 수 있다. (예를 들어 MySQL 5.1은 MariaDB 5.1MariaDB 5.2MariaDB 5.3과 호환되며, MySQL 5.5은 MariaDB 5.5와 호환된다.) 이는 다음과 같은 것을 의미한다.

  • 데이터와 테이블 정의 파일 (.frm) 파일들이 호환된다
  • 모든 클라이언트 API, 프로토콜 및 구조가 동일하다
  • 모든 파일이름, 바이너리, 경로, 포트, 소켓이 모두 동일해야 한다
  • 모든 MySQL 커넥터(PHP, Perl, Python, Java, .NET, MyODBC, Ruby, MySQL C connector 등)는 아무런 변화없이 MySQL에서 잘 작동한다
  • 몇몇 PHP5에서의 설치 이슈가 존재한다. (오래된 PHP 클라이언트가 라이브러리 호환성을 검사하는 데서 발생하는 버그이다)
  • 클라이언트 공유 라이브러리는 MySQL 클라이언트 라이브러리와 호환된다.

이는 대부분의 경우에서 MySQL을 언인스톨한 뒤, MariaDB를 설치해도 잘 작동한다는 것을 의미한다. (동일한 메인 버전에서는 데이터 파일을 변환할 필요없다.)

우리는 월간 주기로 MySQL 코드를 병합하여 호환성을 보장하며 오라클이 추가하는 기능 및 버그 수정도 MariaDB에 포함된다.

우리는 업그레이드 스크립트에 많은 작업을 완료하여 MySQL 5.0에서 MySQL 5.1로 업그레이드하는 것보다 MySQL 5.0에서 MariaDB 5.1로 업그레이드하는 것이 더 쉽도록 하였다.

하지만, MariaDB는 MySQL에 없는 새로운 옵션, 확장, 저장 엔진, 버그 수정도 많이 포함하고 있다. 서로 다른 MariaDB 버전별 기능은 MariaDB 릴리즈별 차이 에서 확인할 수 있다.

MariaDB 5.1과 MySQL 5.1의 비호환성

일부 경우 MariaDB는 MySQL보다 더 많은 정보를 보여주기 위하여 비호환성을 허용하고 있다.

다음 목록은 MySQL 5.1 대신 MariaDB 5.1을 사용하는 경우에 알려진 모든 사용자 레벨의 비호환성 목록이다.

  • 설치 패키지 이름은 MySQL 대신 MariaDB로 시작한다.
  • Timings may be different as MariaDB is in many cases faster than MySQL.
  • MariaDB의 mysqld는 my.cnf에서 [mariadb] 섹션을 읽는다.
  • You can't use a binary only storage engine library with MariaDB if it's not compiled for exactly the same MariaDB version. (This is because the server internal structure THD is different between MySQL and MariaDB. This is common also between different MySQL versions). This should not be a problem as most people don't load new storage engines and MariaDB comes with more storage engines than MySQL.
  • CHECKSUM TABLE은 다른 결과를 출력할 수 있다. MariaDB는 NULL을 무시하지 않지만, MySQL 5.1은 NULL을 무시하기 때문에 이러한 차이가 발생한다. (향후 MySQL은 MariaDB가 계산하는 방식대로 체크섬을 계산해야 할 것이다) 옛날 방식의 체크섬을 얻길 원한다면 --old 옵션으로 MariaDB를 실행하면 된다. 하지만, MariaDB의 MyISAM과 Aria 저장 에닌은 내부적으로 새로운 체크섬을 이용한다. 따라서 --old 옵션을 이용하는 경우 CHECKSUM 명령은 매 레코드마다 체크섬을 계산하기 때문에 속도가 느릴 것이다.
  • 슬로우 쿼리 로그는 쿼리에 대한 더 많은 정보를 제공하는데, 이는 슬로우 쿼리 로그를 직접 파싱하는 경우 문제가 될 수 있다.
  • MariaDB는 내부에서 사용하는 임시 테이블을 기본으로 Aria 저장 엔진을 사용하기 때문에 MySQL보다 메모리를 좀 더 사용한다. MariaDB가 최소한의 메모리만 더 사용하길 원하는 경우 aria_pagecache_buffer_size 를 1M 로 설정하면 된다. (기본 값은 128M).
  • 만약 새로운 명령 옵션MariaDB의 새로운 기능 혹은 새로운 저장 엔진, 을 사용하는 경우 더 이상 MySQL과 MariaDB 사이를 오갈 수 없다.

MariaDB 5.2와 MySQL 5.1의 비호환성

Incompatibilities between MariaDB 5.2 and MySQL 5.1

MariaDB 5.1과 MySQL 5.1의 비호환성과 동일하며 1가지가 추가된다.

SQL_MODE에 새로운 값이 추가되었다. 새롭게 추가된 값은 IGNORE_BAD_TABLE_OPTIONS이며, 이 값이 설정되지 않은 경우, 현재 사용 중인 저장 엔진에서 지원되지 않는 테이블, 필드, 인덱스의 속성을 사용하는 경우 에러를 발생한다. 이런 변화로 인해 에러 로그에는 다음과 같은 경고 메시지가 발생할 수 있다. "mysql 데이터베이스에 잘못 정의된 테이블이 있음. mysql_update를 이용하려 수정하시오"

모든 실용적인 목적에서 MySQL 5.2는 MariaDB 5.1과 MySQL 5.1을 즉시 대체 가능하다.

MariaDB 5.3, MySQL 5.1, MariaDB 5.2의 비호환성

  • 잘못된 변환에 관련된 일부 에러 메시지가 MariaDB에서 좀 더 자세히 제공된다.
  • MariaDB에 특화된 오류 번호는 1900번부터 시작하여 MySQL 오류 번호와 충돌되지 않는다.
  • MySQL은 일부 문맥에서 datetime과 time에서 마이크로초를 손실했지만, MariaDB는 모든 문맥에서 마이크로초가 잘 작동한다.
  • UNIX_TIMESTAMP (상수 날짜 문자열)은 MariaDB에서는 마이크로초 단위까지 표현이 가능히지만 MySQL은 그렇지 못하다. 이는 UNIX_TIMESTAMP()를 파티션 함수로 사용하는 경우 문제가 될 수 있는데, FLOOR(UNIX_TIMESTAMP(..)) 를 이용하거나 날짜 문자열을 숫자형 (예를 들어 20080101000000 형식)으로 바꿔서 해결할 수 있다.
  • MariaDB는 date, datetime, timestamp 값에 대해 더 엄격한 검사 수행한다. 예를 들어 UNIX_TIMESTAMP('x') 는 0이 아닌 NULL을 반환한다.
  • --maria- 시작 옵션은 제거되었다. 대신에 --aria- prefix를 사용해야 한다. (MySQL 5.2는 --maria--와 --aria- 모두 지원함)
  • SHOW PROCESSLIST는 Progress라는 추가적인 컬럼이 존재하며 일부 명령에 대해 진행 상황을 보여준다. 이 기능은mysqld 시작 시 --old 옵션을 이용하여 끌 수 있다.
  • INFORMATION_SCHEMA.PROCESSLIST는 진행 보고를 위해 다음과 같은 3개의 추가적인 컬럼을 출력한다: STAGEMAX_STAGE, and PROGRESS.
  • /*M! 혹은 <<code>>/*!#<</code>로 시작하는 긴 주석은 주석이 아니라 실제 실행이 된다.
  • max_user_connections=0 는 연결 수를 제한 두지 않는 것을 의미하는데, mysqld 시작 시 이 옵션을 사용하는 경우 mysqld가 실행 중인 경우는 이 전역 변수를 수정할 수 없다. <<code>>max_user_connections=s<</code>로 mysqld가 시작된 경우 연결 개수를 위한 구조체를 할당하지 않기 때문이다. mysqld 실행 중에 이 값을 바꾸고 싶다면 0이 아닌 큰 값을 지정하는 것이 좋다.
  • max_user_connections를 -1로 설정하여 (전역 변수인 GRANT 옵션도 동시에) 사용자가 서버에 접속하는 것을 중지시킬 수 있다. 전역 변수 max_user_connections는 SUPER 권한을 가진 사용자에게는 영향을 미치지 않는다.
  • |IGNORE 지시자는 모든 오류를 무시하지 않는다 (예:FATAL 오류). 무시를 해도 안전한 오류만 무시한다.

MariaDB 5.3과 MySQL 5.3의 비호환성

XtraDB

XtraDB를 제공하는 Percona는 5.5 코드 기반에게 초기 기능의 모든 것을 제공하지 않았따. 따라서 MariaDB 5.5 또한 그 기능을 제공하지 못한다.

5.5에 없는 XtraDB 옵션들

다음의 옵션들은 XtraDB 5.5에서 지원되지 않는다. 만약 당신이 my.cnf에서 아래의 옵션을 사용 중이라면 5.5로 업그레이드 전에 제거해야 한다.

  • innodb_adaptive_checkpoint ; Use innodb_adaptive_flushing_method instead.
  • innodb_auto_lru_dump ;Use innodb_buffer_pool_restore_at_startup instead.
  • innodb_blocking_lru_restore ; Use innodb_blocking_buffer_pool_restore instead.
  • innodb_enable_unsafe_group_commit
  • innodb_expand_import ; Use innodb_import_table_from_xtrabackup instead.
  • innodb_extra_rsegments ; Use innodb_rollback_segment instead.
  • innodb_extra_undoslots
  • innodb_fast_recovery
  • innodb_flush_log_at_trx_commit_session
  • innodb_overwrite_relay_log_info
  • innodb_pass_corrupt_table ; Use innodb_corrupt_table_action instead.
  • innodb_use_purge_thread
  • xtradb_enhancements

기본 값이 변경된 XtraDB의 옵션

XtraDB options that has changed default value

옵션기존 값새로운 값
innodb_adaptive_checkpointTRUE?FALSE
innodb_change_bufferinginserts?all
innodb_flush_neighbor_pages1?area

XtraDB 5.5의 새로운 옵션

다음의 옵션들은 XtraDB / InnoDB 5.5에 새롭게 추가된 옵션이다. (Listed here just to have all XtraDB information in the same place)

  • innodb_adaptive_flushing_method
  • innodb_adaptive_hash_index_partitions
  • innodb_blocking_buffer_pool_restore
  • innodb_buffer_pool_instances
  • innodb_buffer_pool_restore_at_startup
  • innodb_change_buffering_debug
  • innodb_corrupt_table_action
  • innodb_flush_checkpoint_debug
  • innodb_force_load_corrupted
  • innodb_import_table_from_xtrabackup
  • innodb_large_prefix
  • innodb_purge_batch_size
  • innodb_purge_threads
  • innodb_recovery_update_relay_log
  • innodb_rollback_segments
  • innodb_sys_columns
  • innodb_sys_fields
  • innodb_sys_foreign
  • innodb_sys_foreign_cols
  • innodb_sys_tablestats
  • innodb_use_global_flush_log_at_trx_commit
  • innodb_use_native_aio

5.5로 업그레이를 위한 Percona의 가이드 도 참조하는 것이 좋다.

MariaDB 5.5MariaDB 5.3과 MySQL 5.5의 비호환성

  • 중복 키 오류에서 INSERT IGNORE 는 경고 메시지를 출력한다.

MariaDB 10.0과 MySQL 5.6의 비호환성

  • MySQL의 모든 바이너리 (mysqldmyisamchk 등)은 예를 들어 --big-tables 대신 --big-table 옵션을 사용하는 경우 경고 메시지를 출력하는 반면, MariaDB 바이너리는 다른 대부분의 유닉스 명령들과 동일한 방식으로 작동하며, 유일한 prefix로 사용될 경우 경고를 출력하지 않는다.

지원되지 않는 설정

my.cnf에서 다음의 옵션을 사용 중인 경우 해당 변수를 제거해야 한다. 이는 MySQL 5.1 및 그 이후 버전에서도 마찬가지다.

  • skip-bdb

MySQL RPM 교체

만약 MySQL RPM을 제거하고 MariaDB를 설치하고자 하는 경우 MySQL RPM은 /etc/my.cnf를 /etc/my.cnf.rpmsave로 이름을 변경한다.

MariaDB를 설치한 뒤에는 다음과 같이 MySQL RPM 당시의 my.cnf를 복원할 수 있다.

mv -vi /etc/my.cnf.rpmsave /etc/my.cnf

MariaDB와 MySQL-Proxy의 비호환성

MySQL 클라이언트 API는 MySQL-Proxy를 통하여 MariaDB에 연결할 수 있다. 그러나 MariaDB 클라이언트 API는 "진행 보고(progress reporting)"을 MySQL-Proxy가 지원하지 않는다는 정보를 받게 된다. 완벽한 호환성을 위해서는 "진행 보고"를 클라이언트 측이나 서버 측에서 중지시키면 된다.


반응형
반응형

MySQL의 버전별 기능(Features) 변경 이력



출처 : http://intomysql.blogspot.kr/2011/01/mysql-features.html


VersionFeatures
추가변경삭제
5.5
  • MyISAM 대신 InnoDB가 MySQL의 기본 스토리지 엔진으로 채택
  • 5.4.2
  • Plugin버전의 InnoDB가 Builtin 버전으로 다시 적용
  • 5.1.38
  • InnoDB Plugin
  • 5.1.24
    (Enterprise version)

  • "SHOW PROFILE"
  • 5.1.12
  • "general_log" 파라미터

  • General query log를 동적으로 변경 가능
  • 5.1.8
  • "Mixed" 복제 모드
  • 5.1.6
  • Partition pruning 기능
  • 5.1.5
  • EXPLAIN PARTITIONS(파티션 테이블의 실행 계획) 지원
  • "RBR"(Row Based Replication) 복제 모드
  • 5.1
  • Plugin API 도입
  • Plugin버전의 InnoDB 릴리즈 (InnoDB 의 많은 성능 개선과 변화가 있음)

  • BDB 스토리지 엔진
  • 5.0.32
    (Community version)

  • "SHOW PROFILES"
  • 5.0.7
  • LIMIT의 파라미터도 PreparedStatement에서 변수화 가능
  • 5.0.5
  • BIT 데이터 타입이 MEMORY, InnoDB, BDB, NDBCLUSTER 스토리지 엔진에 구현됨
  • 5.0.3
  • FEDERATED 스토리지 엔진
  • 신규 함수 추가
    STDDEV_POP()
    STDDEV_SAMP()
    VAR_POP()
    VAR_SAMP()

  • BIT 데이터 타입이 TINYINT와 호환성 없어짐


  • NUMERIC와 DECIMAL 타입의 저장 방식이 String에서 Binary로 변경
  • 5.0.2
  • TRIGGER 도입

  • HAVING 조건에 SELECT컬럼, GROUP-BY컬럼, OUTER-서브쿼리의 값 사용 가능(ANSI 표준)
  • 5.0.1
  • VIEW 도입

  • HAVING 조건에 SELECT컬럼, GROUP-BY컬럼, OUTER-서브쿼리의 값 사용 가능(ANSI 표준)
  • 5.0
  • StoredRoutine (Procedure,Function) 도입
  • CURSOR 도입
  • Archive 스토리지 엔진
  • INFORMATION_SCHEMA 딕셔너리 데이터베이스 도입 (ANSI 표준)

  • ISAM 스토리지 엔진 제거
  • 4.1.11
  • Blackhole 스토리지 엔진
  • 4.1.4
  • CVS 스토리지 엔진
  • 4.1
  • SubQuery 도입
  • WHOW WARNINGS
  • CREATE TABLE ... LIKE ...
  • GROUP_CONCAT() 구현
  • 유니코드(UTF8, UCS2) 지원
  • GIS 관련 기능(Spatial extension) 지원
  • ALTER DATABASE 명령 지원
  • DUAL 테이블 내부 지원(타 DBMS와의 호환성 유지)
    "SELECT 1" 명령과 "SELECT 1 FROM DUAL" 명령은 동일
  • Memory 스토리지 엔진에서 B-Tree 허용
  • EXPLAIN EXTENDED 구현

  • Column 코멘트 구현(CREATE TABLE...)
  • PASSWORD() 함수의 알고리즘 업그레이드
    기존 알고리즘은 OLD_PASSWORD()로 변경됨
  • CHAR, VARCHAR 타입의 길이가 바이트수에서 문자수로 변경됨
  • 파생 테이블(Derived tables) 내에서 UNION 사용 가능
  • 4.0.18
  • "TYPE" 키워드가 "ENGINE" 키워드로 변경(CREATE TABLE...)
  • 4.0.14
  • InnoDB의 BLOB와 TEXT 타입에 대한 인덱스 지원
  • 4.0.4
  • JOIN DELETE (Multiple Delete) 도입
  • JOIN UPDATE (Multiple Update) 도입
  • 4.0.2
  • Memory 스토리지 엔진에서 NULLABLE 컬럼의 인덱스 지원

  • VARCHAR 컬럼의 길이가 1~255에서 0~255로 변경됨
  • 4.0.1
  • Query Cache 도입
  • 4.0
  • UNION 집합 연산 도입
  • SQL_CALC_FOUND_ROWS 힌트와 FOUND_ROWS() 함수 구현

  • UPDATE와 DELETE 구문에 ORDER BY 사용 허용
  • 3.23
  • EXPLAIN(쿼리 실행계획) 구현
  • 전문 검색(Fulltext search) 도입
  • JOIN(SELECT만) 도입
  • NULL-SAFE 연산자(<=>) 도입

  • 길이가 0인 CHAR 컬럼 허용

  • 반응형
    반응형


    오랜만에 포스팅한다.


    파이썬 스크립트 개발에 틈틈히 php 수정등...

    마리아 DB를 공부도 해야된다는 생각에 정신이 없다..

    하지만 이게 잘 하고 있는건지...라는 의문의 1패...


    잡설은 그만하고..


    Script로 백업 도중 (스크립트 뽑아내는 명령어 중) Lock Tables 라는 에러가 발생하였다.


    그동안 문제없이 잘 돌아가는 스크립트가 왜 지금 에러가 발생했을까 라는 의문도 들고..

    중간에 작업한 적이 없는 것 같은데 ...


    하지만 컴퓨터는 거짓말을 하지 않기에... 일단은 백업이 우선이라 해결을 진행해 보았다.



    MyISAM 이기에 배치 작업이 있나 확인을 해 보았다. (조회 또한 table lock 을 잡기에....이건 순수히 나만의 생각)


    show processlist;


    하지만 확인 결과 어떠한 작업도 확인이 되지 않았다.


    그렇다면 희박하지만 권한을 부여해 보았다. (권한을 revoke 한 적은 전혀 없기에...)


    mysql> GRANT SELECT,LOCK TABLES ON DBNAME.* TO 'username'@'localhost';


    이 후 다시 진행해 보았다.


    $mysqldump -d -u유저 -p --quick > /파일명.sql 


    말도 안되....정상적으로 진행이 되었다.


    하아....누가??아니면 무슨 이유로...??

    원인을 찾아 봐야겠다.

    반응형

    + Recent posts