MySQL 클러스터는 분산 컴퓨팅 환경에서 high-availability와 high-redundancy를 채택하였다. MySQL 클러스터는 NDB 클러스터 스토리지 엔진을 사용하여, 클러스터에서 여러 개의 서버가 함께 돌아가도록 한다. MySQL 클러스터가 지원하는 운영 체제는 Linux, Mac OS X, Solaris 등 이다. 더 자세한 정보는 다음 사이트를 참고 하길 바란다. http://www.mysql.com/products/cluster
MySQL 클러스터는 share-nothing 시스템에서 in-memory 데이터 베이스의 클러스터링을 가능하게 한다. 이러한 아키텍쳐는 특정한 하드웨어 및 소프트웨어를 요구하지 않으므로 비용을 절감할 수 있도록 하며, 각 콤포넌트가 고유 메모리와 디스크를 보유함으로 단일 취약점(single point of failure)을 가지지 않는다.
MySQL 클러스터는 일반 MySQL 서버에 NDB라는 스토리지 엔진을 통합하여, 다음 그림과 같이 MySQL서버, NDB 클러스터의 데이터 노드, MGM 서버가 포함된 컴퓨터와 데이터에 접근하기 위한 어플리케이션 프로그램으로 구성된다.
데이터가 NDB 클러스터 스토리지 엔진에 저장될 때, 테이블은 데이터 노드에 저장된다. 각 테이블은 클러스터의 MySQL 서버에서 직접 접근이 가능하다. 그래서 클러스터의 어떤 정보를 업데이트 하면, 다른 모든 MySQL서버에서 곧바로 확인할 수 있다.
MySQL 클러스터의 데이터 노드에 저장된 데이터는 미러링이 가능하며, 클러스터는 트랜잭션 중단 등 각 노드들의 상태에 대한 핸들링이 가능하다.
NDB는 높은 가용성과 데이터 지속성을 갖는 인 메모리 스토리지 엔진이다. DB 스토리지 는 failover와 로드 밸런싱 옵션을 설정할 수 있다. MySQL클러스터는 NDB 스토리지 엔진과 MySQL 서버로 구성되어 있으며, MySQL 클러스터의 클러스터 부분은 MySQL 서버에 독립적이다. MySQL 클러스터의 각 부분은 노드로 간주한다.
클러스터 노드에는 세 가지 타입이 있으며, MySQL Cluster를 구성하기 위해 최소한 노드 세 개가 있어야 한다.
MGM node : 이 노드는 설정을 포함, 다른 노드를 관리하는 매니저 노드이다. 다른 노드보다 가장 먼저 실행되며 ndb_mgmd 명령으로 실행시킨다.
data node : 클러스터의 데이터를 저장하는 노드이다. ndbd 명령으로 실행시킨다.
SQL node : 클러스터 데이터에 접근하는 노드이다. MySQL 클러스터에서는 NDB 클러스터 스토리지 엔진을 사용하는 MySQL 서버가 클라이언트 노드이다. mysqld --ndbcluster나 mysqld 명령으로 실행시키는데, 이 때는 my.cnf 에 ndbcluster를 추가한다.
MGM 노드는 클러스터 컨피그레이션 파일과 로그를 관리한다. 데이터 노드에 이벤트가 발생하면, 데이터 노드는 그에 대한 정보를 매니저 서버로 보내고, 매니저 서버는 클러스터 로그를 기록한다.
Simple Multi-Computer How-To
다음과 같이 4대의 컴퓨터로 클러스터를 구성하는 것을 가정하고 있다. (4개의 노드로 구성되고, 각각의 노드는 편이성을 위해 IP로 지칭한다.)
아래에서 필요한 컴퓨터는 리눅스가 설치된 인텔 기반 데스크탑 PC이며, 4대 모두 동일한 이더넷 카드(100Mbps나 1기가 비트)가 필요하다.
7. 각 데이터 노드와 SQL 노드는 MySQL서버 옵션과 connectstring에 대한 정보가 포함된 my.cnf파일이 필요하고, MGM노드는 config.ini 파일이 필요하다. 에디터를 열어 다음과 같이 편집한 후 파일을 저장한다.
# vi /etc/my.cnf
[MYSQLD] # Options for mysqld process:
Ndbcluster # run NDB engine
ndb-connectstring=192.168.0.10 # location of MGM node
[MYSQL_CLUSTER] # Options for ndbd process:
ndb-connectstring=192.168.0.10 # location of MGM node
8. MGM 노드의 설정 파일을 만들기 위해 적당한 디렉토리를 만든 후 에디터를 열어 다음과 같이 편집한다.
# mkdir /var/lib/mysql-cluster
# cd /var/lib/mysql-cluster
# vi config.ini
[NDBD DEFAULT] # Options affecting ndbd processes on all data nodes:
NoOfReplicas=2 # Number of replicas
DataMemory=80M # How much memory to allocate for data storage
IndexMemory=18M # How much memory to allocate for index storage
# For DataMemory and IndexMemory, we have used the
# default values. Since the "world" database takes up
# only about 500KB, this should be more than enough
# for this example Cluster setup.
[TCP DEFAULT] # TCP/IP options:
portnumber=2202 # This the default; however, you can use any
# port that is free for all the hosts in cluster
# Note: In MySQL 5.0, this parameter is deprecated;
# it is recommended that you do not specify the
# portnumber at all and simply allow the port to be
# allocated automatically
[NDB_MGMD] # Management process options:
hostname=192.168.0.10 # Hostname or IP address of MGM node
datadir=/var/lib/mysql-cluster # Directory for MGM node logfiles
[NDBD] # Options for data node "A":
# (one [NDBD] section per data node)
hostname=192.168.0.30 # Hostname or IP address
datadir=/usr/local/mysql/data # Directory for this data node's
# datafiles
[NDBD] # Options for data node "B":
hostname=192.168.0.40 # Hostname or IP address
datadir=/usr/local/mysql/data # Directory for this data node's
# datafiles
[MYSQLD] # SQL node options:
hostname=192.168.0.20 # Hostname or IP address
datadir=/usr/local/mysql/data # Directory for SQL node's datafiles
# (additional mysqld connections can be
# specified for this node for various
# purposes such as running ndb_restore)
설치와 설정 과정이 끝났다. 이제 실행을 해 보자.
클러스터 노드들은 각각 실행되어야 한다. 실행 순서는 매니지먼트 노드를 가장 먼저 실행할 것을 권한다. 그 다음은 스토리지 노드와 SQL노드 순이다.1. 매니지먼트 호스트에서 MGM 노드 프로세스를 실행시켜 보자. 컨피그레이션 파일을 찾을 수 있도록 -f 옵션을 주도록 한다.
# ndb_mgmd -f /var/lib/mysql-cluster/config.ini
MGM 노드를 다운시킬 때에는 다음과 같이 하면 된다.
# ndb_mgm -e shutdown
2. 다음으로 데이터 노드 호스트에서 NDBD프로세스를 실행시킨다. --initial 이란 인수는 ndbd를 처음 실행할 때와 컨피그레이션이 바뀐 후 재시작 할 때만 사용한다.
# ndbd --initial
3. SQL 노드는 다음과 같이 mysql.server를 실행시킨다.
# /etc/rc.d/init.d/mysql.server start
4. 이제 모든 노드가 실행되었으니 MGM 노드 클라이언트를 띄워 간단히 테스트를 해보자.
Ndb_mgm명령어를 입력하였을 때 정상적으로 동작하는 모습은 다음과 같이 프롬프트가 떨어지는 모습이다.
리플리케이션은 비동기화 방식이고, 클러스터는 동기화 방식이다. 따라서 리플리케이션은 일방적으로 데이타를 전달하여 복제를 하지만 클러스터는 동기방식이므로 데이타를 복제한 후 결과를 확인하기 때문에 데이타 누락이 발생하지 않는다. 다만 복제한 결과를 확인해야 하기 때문에 Cluster가 Replication보다는 속도가 느리다. 또한 Replication의 경우 복제된 데이터에 대한 신뢰를 할 수 없다.
Cluster가 사용하는 네트워크 (How do computers in a cluster communicate?)
MySQL 클러스터는 TCP/IP를 통해 서로 통신한다. 최소한 100Mbps의 이더넷을 사용해야 하며 원활한 통신을 위해 gigabit 이더넷을 권고한다. 실제 데이터가 메모리에 존재하여 사용되며 물리적인 측면에서 봤을 때 CPU, 메모리, 각 노드간의 통신을 위한 네트워킹이 주를 이룬다. 이중 가장 속도가 느린 네트워크의 속도를 높임으로써 전체적인 빠른 동작이 가능하도록 해야 한다. 또한, 더욱 빠른 SCI 프로토콜도 지원하며, 이는 특정 하드웨어를 필요로 한다.
클러스터를 구성하기 위해 컴퓨터가 얼마나 필요한가?
최소한 3대가 있어야 클러스터 구성이 가능하나, MGM 노드와 SQL 노드, 스토리지 노드 둘, 이렇게 4 대로 구성하길 권한다. 하나의 노드가 실패했을 때 지속적인 서비스를 하기 위해서 MGM노드는 분리된 컴퓨터에서 실행되어야 한다.
클러스터에서 각 컴퓨터들이 하는 일은?
MySQL 클러스터는 물리적, 논리적으로 구성된다. 컴퓨터는 물리적 요소이며 호스트라고 불리기도 한다. 논리적, 기능적 요소는 노드이다. 노드는 역할에 따라 MGM 노드, data 노드(ndbd), SQL 노드로 나뉜다.
어떤 OS에서 사용할 수 있는가?MySQL 4.1.12 현재 MySQL 클러스터는 공식적으로 Linux, Mac OS X, Solaris를 지원한다.
일반적으로 Cluster는 하나의 업무를 수행하기 위해 함께 동작하는 컴퓨터 세트이다. NDB Cluster는 자료저장, 복구, 컴퓨터 간의 분배 관리 등을 시행하기 위해 MySQL을 사용하는 Storge Engine 이다. MySQL Cluster는 in-memory storage를 사용한 shared-noting 아키텍쳐에서 분산된MySQL DB를 지원하기 위해 NDB엔진을 사용하여 함께 돌아가는 컴퓨터 그룹이다.
Configuration Files
클러스터, 호스트, 노드에 관계된 직접적인 정보를 포함하는 파일이다. 클러스터 시작 시 Cluster의 MGM 노드가 읽어들인다.
Backup
디스크나 다른 Long-term Storage에 저장되는 모든 클러스터 데이타, 트랜젝션, 로그의 완전한 카피를 말한다.
일반적으로 데이타가 디스크에 저장될 때 체크포인트에 도달한다고 말한다. 클러스터에서는 Committed된 트랜잭션을 디스크에 저장하는 시간을 말한다. NDB Storage Engine에는 일관되게 클러스터의 데이타를 보존하기 위해 두 종류의 CheckPoint가 있다. LocalCheckPoint(LCP) : 싱글 노드의 체크포인트. 그러나 클러스터의 모든 노드에서 LCP를 사용한다. LCP는 디스크에 노드의 모든 데이타를 저장하도록 한다(보통 매 몇 분마다). 클러스터 Activity의 노드와 레벨, 다른 요인에 의해 저장되는 데이타의 양은 의존적이다. GlobalCheckPoint(GCP) : GCP는 모든 노드의 트랜잭션이 동기화되고, redo-log가 Disk에 저장될 때 몇 분마다 발생한다.
Cluster Host
MySQL Cluster의 구성 컴퓨터. 클러스터는 물리적 구조와 논리적 구조를 가진다. 물리적으로 클러스터는 Cluster Host라는 컴퓨터의 수로 구성된다.
Node
MySQL Cluster의 논리적, 기능적 요소를 말하며 Cluster Node라고도 한다. MySQL Cluster에서는 node란 용어를 Cluster의 물리적 Component인 Process를 지칭한다. MySQL Cluster가 동작하기 위해 3가지 타입의 노드가 있다.
MGM node - MySQL Cluster에서 다른 노드들의 설정 정보, 노드의 시작과 정지, 네트워크 파티셔닝, 백업과 저장 등을 포함하여 다른 노드들을 관리한다.
SQL node (MySQL Server) - 클러스터의 데이터 노드안에 저장된 데이터를 Serve 하는 MySQL Server 인스턴스. 데이타를 저장, 분배, 업데이트하는 클라이언트는 MySQL Server를 통해 접근 가능하다.
Data node - 이 노드는 실제 데이타를 저장한다. 현재 싱글 클러스터는 총 48개의 데이타 노드를 지원한다.
싱글 머신에 한 개 이상의 노드가 공존할 수도 있고, 한 머신에 완전한 클러스터를 구성하는 것도 가능하다. MySQL 클러스터에서 호스트는 클러스터의 물리적 컴퍼넌트이며, 노드는 논리적 혹은 기능적인 컴퍼넌트, 즉 프로세스라는 것을 잊지 말자.
Node group
데이터 노드의 집합. 노드 그룹 안의 모든 데이터 노드는 같은 데이터(fragment)를 포함한다. 그리고 싱글 그룹의 모든 노드는 다른 호스트에 존재해야 한다.
Node failure
MySQL 클러스터는 클러스터를 구성하는 어느 한 노드의 기능에만 의존적이지 않다. 클러스터는 하나 혹은 몇 개의 노드가 실패해도 계속될 수 있다.
Node restart
실패한 클러스터 노드의 리스타팅 과정.
Initial node restart
노드의 이전의 파일 시스템을 지우고 시작하는 클러스터 노드의 과정. 소프트웨어 향상과 그 밖의 특별한 상황 등에 사용된다.
System crash(or System fail)
클러스터의 상태가 확인되지 않는 등 많은 클러스터 노드가 실패했을 때 일어날 수 있다.
System restart
클러스터의 리스타팅과 디스크 로그 및 체크 포인트로부터 reinstall하는 프로세스를 말한다. 클러스터를 shutdown 한 이후에 일어나는 과정이다.
fragment
데이터베이스 테이블의 한 부분. NDB스토리지 엔진에서 테이블을 나누어 fragments의 수에 따라 저장한다. Fragment는 파티션이라 불리기도 한다. MySQL 클러스터에서 테이블은, 머신과 노드 간의 로드 밸런싱을 용이하게 할 수 있도록 fragment된다.
Replica
NBD 스토리지 엔진에서 각 테이블 프레그먼트는 여분을 포함하여 다른 데이터 노드에 저장된 많은 replica를 갖는다. 현재는 fragment 당 4개 이상의 replica가 가능하다.
Transpoter
노드들 간의 데이터 이동을 제공하는 프로토콜 TCP/IP(local), TCP/IP(remote), SCI, SHM(MySQL 4.1 버전에서 실험적임)
NDB는 MySQL클러스터에서 사용하는 스토리지 엔진을 말 함. NDB 스토리지 엔진은 모든 일반적인 MySQL 컬럼 타입과 SQL문을 지원하며, ACID(DB무결성 보장을 위한 트랜잭션)성질을 가진다.
Shared-nothing architecture
MySQL 클러스터의 이상적인 아키텍쳐. 진정한 Shared-nothing setup 에서 각 노드는 분리된 호스트에서 실행된다. 이러한 배열은 싱글 호스트나 싱글 노드가 아니면 SOF나 시스템 병목현상이 전체적으로 발생할 수 있다는 데 있다.
In-memory storage
각 데이터 노드에 저장된 모든 데이터는 그 노드의 호스트 컴퓨터의 메모리에 유지된다. 클러스터의 각 데이터 노드를 위해, (데이터 노드의 수로 나뉜 replica의 수 * 데이터베이스 사이즈)만큼의 가용 RAM의 양을 확보해 두어야 한다. 그러니까, 데이터베이스가 1기가의 메모리를 차지하고, 4개의 replica와 8개의 노드로 클러스터를 구성하고자 하면, 각 노드당 최소 500MB의 메모리가 필요하다. 그리고 OS와 다른 어플리케이션 프로그램이 쓰는 메모리가 추가로 필요하다.
Table
관계형 데이터베이스에서는 table은 일반적으로 동일하게 구조화된 레코드의 set을 가리킨다. MySQL 클러스터에서 데이터베이스 테이블은 fragment의 set으로써 데이터 노드에 저장되고, 각 fragment는 추가로 데이터 노드에 복제된다. 같은 fragment를 replicate한 데이터 노드의 set이나 fragment의 set을 노드 그룹이라 한다.
최근 인터넷 서비스들은 글로벌을 지향하고 소셜 네트워크 기능들을 추가하다 보니 데이터의 양과 트래픽의 양이 급속히 증가하고 있다. 또한 가용성 확보 목적으로 RDBMS도 이젠 스케일아웃(Scale-Out)에 자유롭지 못한 상황에 놓이게 되었다. RDBMS가 여러 측면에서 최상의 조합 기능을 제공하지만, 개별 영역의 장점을 추구하는 솔루션들보다 좋은 성능을 낼 수 없는 건 당연하다. 스케일아웃 관점에 맞는 솔루션을 찾을 필요가 있어 MySQL의 스케일아웃 측면에서 어떤 솔루션들이 있는지 살펴보고자 한다.
[필자] 하호진 | KTH에서 포털 서비스 및 플랫폼(Identity/Payment) 개발 업무를 수행했으며, 현재 와이즈에코에서 이사로 일하고 있다. 개인 블로그 mimul.com/pebble/default를 운영한다.
1. MySQL Partitioning
1) 개요
파티셔닝은 대규모 테이블을 여러 개의 작은 파티션으로 분할해 성능을 높이는 기술이다. 각 행에 대해 각각의 파티션에 분할하며, MySQL에서는 5.1버전부터 지원한다. 파티셔닝은 주로 데이터 웨어하우스와 같은 거대한 테이블을 사용하는 경우에 위력을 발휘한다. 일반적으로 B 트리 인덱스가 커지면서 검색 및 삽입 속도가 저하된다(계산 순서는 O(log m N)). 하지만, 테이블을 파티션으로 나누는 것으로, B 트리 인덱스의 오버헤드를 줄일 수 있다.
그림 1 파티션된 테이블
파티션 테이블은 데이터의 분류 조건에 의해 여러 개의 작은 파티션으로 나뉘어 저장된다.
+ 제약 사항 - 파티셔닝된 테이블은 스토리지 엔진이 같아야 한다. -외부키 제약은 사용할 수 없다. -FULLTEXT 인덱스를 사용할 수 없다. -GIS 컬럼을 사용할 수 없다. -임시 테이블, MERGE 스토리지 엔진, CSV 스토리지 엔진은 파티셔닝할 수 없다.
2) 방식
+ RANGE 파티션마다 칼럼의 값이 취할 범위를 지정하는 방식이다.
+ LIST
파티션 마다 칼럼의 값을 직접 지정하는 방식이다.
+ HASH HASH 값을 갖고 파티션을 할당하고, 할당이 사용자에 의해 정해지는 것이 아니라 MySQL에 맡기는 방식이다.
파티션 방식의 수식을 좀 더 이해하기 쉽게 설명하면, 내부적으로‘2012-05-15’라는 입력 값이 들어간다면 birthday가 아래와 같이 처리되어 파티션 1에 저장된다.
+ KEY
HASH와 비슷하나 분할 결정 값은 Primary Key(혹은 Unique Key)에 대해 서버 측의 결정 알고리즘(MySQL 클러스터:MD5, 다른 스토리지 엔진:PASSWORD())에 의해 결정되는 방식이다. - PRIMARY/UNIQUE 키가 없으면 사용 불가 - UNIQUE 키가 NOT NULL이 아니면 불가(NULL 값은 MD5, PASSWORD 함수 적용 불가)
+ 서브 파티셔닝 RANGE와 LIST일 때 각 파티션을 더 분할할 수가 있다. 이것을 서브파티션이라고 한다.
3) 장단점
+ 장점 - 대량의 데이터 저장 - 테이블을 분할할 수 있기 때문에 많은 양의 데이터를 저장할 수 있다.
- 부하 경감 - 테이블의 데이터를 분할할 수 있어서 쿼리에 검색되는 데이터가 줄어든다. - 해당 디스크에 남아있는 분할 데이터를 받을 확률이 높기 때문에 캐시 히트율도 높아진다. - 집계 함수(SUM/COUNT)가 병렬 처리가 가능해 속도 향상을 가져 온다.
+ 단점 - 분할 방법의 정의, 관리, 그것을 취급하는 애플리케이션 측의 구현, 조사 비용 등이 증가한다.
4) 고려사항
+ 장점 -테이블 설계 시 PK는 파티셔닝키와 연관돼야 하고 PK를 제외한 추가 제약 조건은 불가능하만, 테이블 특성에 맞는 것들만 파티셔닝 테이블로 설계해야 한다. 그리고 파티셔닝 키가 모든 조회 조건에 들어가야 한다는 점도 유의해야 한다. ? 그 외는 1) 개요의 제약 사항을 참고하기 바란다.
2. MySQL Cluster
1) 개요
MySQL Cluster는 공유 디스크를 사용하지 않는 Active-Active 형태의 데이터베이스 클러스터에서 트랜잭션을 지원하고 MySQL의 SQL 문장을 사용할 수 있는 관계형 데이터베이스이다. 단일 장애 지점을 없애기 위하여 99.999%의 가용성(연간 5분 정도의 정지시간)을 달성하기 위한 설계가 반영돼 있다. 데이터를 여러 서버에 분산함으로써 동시 다발적으로 대량으로 발생하는 데이터 업데이트를 신속하게 처리하고, 확장성을 높인 접근이다. 온라인 백업뿐만 아니라 클러스터에 서버 추가와 업데이트도 온라인 상태에서 할 수 있기 때문에 클러스터를 중단 없이 운용할 수 있다. MySQL Cluster의 시발점은 통신장비 업체 에릭슨 휴대 통신망의 가입자 데이터베이스용으로 개발된 Ericsson Network DataBase(NDB)라고 한다. 2003년부터 MySQL 서버의 기능과 통합해 제품화하고, 현재 MySQL 서버와 별도의 제품으로 개발?판매가 진행되고 있다.
+아키텍처 MySQL Cluster에서 공유 디스크를 사용하지 않는 대신 여러 서버에 데이터를 분산 배치하고, 항상 여러 서버가 동일한 데이터 사본을 갖고 있게 한 접근이다. 각 노드의 특성은 다음 <표 1>과 같다.
각 테이블의 기본 키 또는 고유 키의 해시를 계산해 파티션을 내부적으로 만들고, 해시 값과 데이터 노드의 수에 따라 각 파티션의 데이터를 데이터 노드에 분산한다. 분산된 데이터는 같은 그룹 데이터 노드의 복제본에 중복 저장된다. 파티션의 데이터가 변경되면 동일한 파티션을 가진 데이터 노드에 동기적으로 변경 사항이 반영되기 때문에 각 데이터 노드의 데이터는 항상 동일하게 유지된다.
그림 2 Cluster
클러스터에 있는 데이터 노드? 비트 패킷을 보내 모니터링하고 데이터 노드가 중지된 경우 클러스터에서 자동으로 분리된다. 또한 재해 복구 데이터 노드는 같은 그룹의 데이터 노드에서 최신 변경사항까지 차이를 취득해 데이터를 자동으로 반영하고 데이터를 동기화할 때 클러스터에 다시 참여한다.
+ 특징 - 자동 파티셔닝 - 분산 프라그먼트 - 동기화 방식 - 자동으로 이뤄지는 고속 데이터 노드
+ 페일오버 - 자동 재동기화 -트랜잭션 지원
+ 제약 사항 - 인메모리 인덱스 - 크로스 테이블 조인, 레인지 스캔 등을 지원 안 함 - 포린키 지원 안 함 - 롱 트랜젝션 지원 안 함 - 네트워크 지연 시 치명적 - 모든 클러스터의 기종은 동일해야 함. 기종에 따른 비트 저장방식이 다른 경우에 문제 발생
2) 방식
+ Shared-Nothing
그림 3 Shared-Nothing
각 데이터 노드별 독립적인 스토리지를 연결하고 스토리지 공유를 하지 않기 때문에 오라클 RAC와는 달라 스토리지 장애 발생 가능성을 차단하는 구조이다.
+Data Partitioning(데이터 분산 구조)
그림 4 Data Partitioning
테이블 Row 단위의 여러 노드에 분산해 쓰기 성능 확장이 가능하고 하나의 노드 그룹 시스템에 동일한 복제본으로 이중화 구성을 했다.
3) 장단점
+ 장점 -고성능?고가용성 - 어플리케이션에서 샤딩 기능이 필요없어 개발 및 유지보수 비용 절감 - Join 실행 가능 - 샤드(Shard) 간 ACID 보장 - 네트워크 홉이 크게 줄어 높은 처리성능과 짧은 대기 시간 제공 - 즉각적인 페일오버 및 복구 지원
+ 단점 - MySQL Cluster 7.2에서 많은 개선이 있었지만 테이블 조인 성능이 떨어짐 - 클러스터 격리 수준이 READ-COMMITTED
4) 고려사항
+ Distribution Awareness 고려한 설계 MySQL Cluster 내에서 데이터의 분산은 이른바 Sharding과 같은 원리로 이뤄지고 있다. 그래서 Distribution Awareness가 제대로 고려되지 않은, 데이터 노드 수가 증가하면 네트워크 병목현상이 일어나 성능 저하를 유발한다. 이를 위해서는 Sharding 방식으로 테이블을 정의하고 응용 프로그램에서 사용하는 쿼리도 조정한다면 효율을 높일 수 있다. 예를 들어 아래와 같이 Distribution Awareness를 이용하기 위해서는 테이블 정의와 쿼리를 조정해야 한다.
그리고 Distribution Awareness가 효과가 있는지 확인하려면 'EXPLAIN PARTITIONS SELECT ...'를 이용해 파티션이 하나만 선택됐는지 확인한다.
+ 키 설계도 중요하다. MySQL Cluster는 Hash 인덱스 및 Ordered 인덱스라는 두 유형의 인덱스가 있다. Ordered 인덱스는 한 테이블에서 여러 개를 만들 수 있지만, 해시 인덱스는 테이블마다 하나만 만들 수 있다. 즉, 해시 인덱스로 구성되는 기본 키뿐이다. 한편, UNIQUE KEY 제약 조건을 이용하는 경우에는 해시 인덱스가 될 수 있다. 하지만 MySQL Cluster에서는 UNIQUE 키를 정의하면 내부적으로 지원 테이블이라는 다른 테이블이 생성된다. 지원 테이블만큼 테이블에 대한 참조가 증가하므로 UNIQUE KEY 제약 조건을 이용하는 키는 성능이 떨어짐을 알아야 한다.
3. MySQL Replication
1) 개요
MySQL은 마스터/슬레이브 복제 기능을 제공한다. MySQL에서 지원하는 것은 비동기식 복제로 마스터 서버에서 실행되는 SQL 문을 슬레이브 서버로 전송하고 슬레이브로 다시 실행해 데이터를 일관되게 유지하는 기법을 사용하고 있다. 이것은 스테이트먼트 기반 리플리케이션(SBR, Statement Based Replication)이라고 한다. SBR는 그 구조에 근본적인 문제가 있다. 예를 들어 UUID() 함수를 사용할 경우 마스터와 슬레이브에서 각각 UUID()를 실행하면, 각기 다른 결과로 나타난다. 그 결과, 마스터와 슬레이브는 데이터가 불일치하게 된다. 이 문제를 해결하려면 슬레이브로 전달되는 정보를 스테이트먼트 대신 실제로 테이블에 기록된 내용 또는 행 자체를 복제한다. 그것을 구현하는 것이 로우 기반 리플리케이션(RBR, Row Based Replication)이다.
MySQL 5.1에서 UUID()을 복제하지 못할 스테이트먼트를 포함할 때만 자동으로 SBR에서 RBR로 전환 MIXED 모드가 기본값(binlog_format)으로 돼 있다.
+아키텍처
그림 5 Replication
MySQL Replication은 READ 관련 스케일아웃만 가능할 뿐, WRITE 관련 스케일아웃은 불가하다. 만약 Replication 운영 시 마스터 트래픽이 과도하게 발생하면, 마스터와 슬레이브 간 데이터 동기화 지연 현상이 발생하기도 한다는 점을 염두에 둬야 한다. 동작의 흐름을 살펴본다면 아래와 같다.
① Slave I/O 스레드가 Master에 접속 ② Master가 Slave를 인증하고 Slave와의 세션 개시 ③ Slave I/O 스레드가 바이너리 로그파일(파일명, 위치)을 요구 ④ Master(binlog dump 스레드)가 요구된 지점으로부터 이벤트를 바이너리 로그에서 읽어 들여 Slave에 전송 ⑤ Slave I/O 스레드는 받아 낸 이벤트를 relay-log에 기록 ⑥ Slave SQL 스레드가 relay-log 내용을 읽어 들여 SQL문을 실행 ⑦ Master에 새로운 이벤트가 있으면 Master가 Slave에 송신
2) 방식
+ Linux Heartbeat + MySQL Replication
그림 6 Heartbeat + MySQL replication
Heartbeat 프로토콜을 사용해 노드 간 생존 확인 메시지를 송수신해 장애 여부를 인지한다. 두 서버 사이에는 가상(Virtual) IP가 위치해 장애 시 가상 IP는 살아있는 서버로 송수신해 장애를 피한다.
+ L/B + MySQL Replication
그림 7 L/B + MySQL Replication
여러 대의 슬레이브를 앞에 두고 부하 분산을 목표로 하며??서 마스터에서 장애가 발생하면 L/B는 자동 IP를 슬레이브로 향하게 해 서비스가 중단 없이 가능하게 된다.
+Linux Heartbeat + DRBD + MySQL Replication
그림 8 Heartbeat + DRBD + MySQL Replication
디스크 미러링 소프트웨어(DRBD; 단방향 복제, 동기 복제, 오픈소스)를 활용해 HA를 구성하는 방식이다. 이는 동기 방식으로 데이터 복제가 이뤄져 데이터 불일치가 없는 장점을 갖고 있다.
3) 장단점
+ 장점 - MySQL 서버의 부하 분산 가능 - 실시간 백업 가능
+ 단점 - 장애가 발생시 슬레이브에 반영이 안 될 가능성 존재 - Master와 Slave 간 데이터 동기화 지연 발생 가능성 존재 - 장애 복구가 수동으로 이뤄짐
4) 고려 사항
+ MySQL 5.6.3에서는 slave multithread를 지원하지만, 이전 버전의 경우 Slave는 하나의 스레드로만 SQL을 실행하기 때문에 서버 간 동기화 지연 현상이 발생한다. 따라서 replicate_do_db 혹은 replicate_do_table 옵션을 사용해 실제로 적용할 객체들만 선별적으로 동기화하는 것이다. 이는 서비스 단위로 기능을 나눌 수도 있고, 역할별로 기능을 나눌 수 있게 할 수 있다. 그 외에 롱 트렌젝션을 제거하고, Slave 개수를 잘 조절하고, 작업 집합이 InnoDB 버퍼 풀보다 훨씬 큰 경우는 Slave pre-fetching 기술도 활용해 볼 만하다.
+ MySQL Replication에서 5.5버전부터 Semi-syncronous 기능이 추가됐다. 부하량이 적은 환경에서 마스터와 슬레이브 간의 데이터 정합성을 강화시키는 방법이므로 필요 시 활용하면 좋다.
4. MySQL Sharding
샤딩은 물리적으로 다른 데이터베이스에 데이터를 수평 분할 방식으로 분산 저장하고 조회하는 방법을 말한다. 여러 데이터베이스를 대상으로 작업해야 하기 때문에 경우에 따라서는 기능에 제약이 있을 수 있고(JOIN 연산 등) 일관성(consistency)과 복제(replication) 등에서 불리한 점이 많다. 과거의 샤딩은 애플리케이션 서버 레벨에서 구현하는 경우가 많았는데 최근에는 이를 플랫폼 차원에서 제공하려는 시도가 많다. 그중 미들티어에 샤딩 플랫폼을 둔 Gizzard, Spider, Spock Proxy에 대해 알아본다.
1) Gizzard
+ 개요 트위터(Twitter)에서 자체 개발한 데이터를 분산 환경에 쉽게 구성?관리하고, 장애 발생에 유연하게 대처할 수 있는 오픈소스이면서 미들웨어다. Gizzard 의 핵심이 되는 것은 샤딩(Sharding)이라는 기술이다. 트위터에 따르면, 샤딩은 파티션과 복제라는 두 기술로 구성됐다. 파티션은 하나의 데이터베이스를 해시 등을 사용해 여러 부분으로 나눔으로써 여러 데이터베이스에 분산하는 것을 말하고, 복제는 한 데이터 복제를 다른 서버에 만드는 것이다. 데이터를 복제해 전체 탄력성이 증가함과 동시에 대량의 액세스에 대해 복수의 서버가 동시에 응답할 수 있기 때문에 성능 향상을 기대할 수 있다.
+ 아키텍처
그림 9 Replication
Gizzard는 데이터 저장소와 클라이언트 애플리케이션 사이에 위치해 모든 질의는 Gizzard를 통해 이뤄지고 있어 Gizzard가 분할?복제 키를 쥐고 있다.
그림 10 Gizzard Partition
① Gizzard 는 데이터 매핑 선행 테이블에서 데이터 조각을 관리한다. 키에 해당하는 값이 어디에 저장됐는지 샤드 정보를 갖고 있다. 특정 데이터에 관한 키 값을 해시 함수로 돌리고 결과값을 Gizzard에 전달하면, Gizzard는 해당 데이터가 어떤 구역에 속할지 숫자 정보를 생성한다. 이러한 함수는 프로그래밍 가능하기 때문에 사용자 성향에 맞춰 지역성 혹은 균형성 면에서 최적화할 수 있다.
그림 11 Gizzard Replication
② Gizzard는 'Replication Tree'로 복제 데이터를 관리한다. 매핑 테이블이 지칭하는 각 데이터 조각들은 물리적 또는 논리적인 형태로 구현될 수 있다. 즉, 물리적인 형태는 특정 데이터 저장소를 의미하고, 논리적인 형태는 데이터 조각에 관한 트리를 의미한다. 트리 안의 각 브랜치들은 데이터의 논리적인 변형을 나타내고, 각 노드들은 데이터 저장소를 의미한다.
③ Gizzard는 장애 상황에도 강한 시스템이다. 특정 파티션 내에 있는 복제 데이터가 유실됐을 지라도, Gizzard는 남은 다른 정상적인 복제 데이터 시스템에 읽기/쓰기를 전환 요청한다. 대응 시나리오는 데이터 조각 안의 특정 복제 데이터 불능이 발생하면 Gizzard는 최대한 빠르게 다른 정상적인 복제 데이터에 읽기/쓰기 작업을 시도해서 정상적인 응답을 주고, Gizzard 내부에서도 문제가 발생했던 복제 데이터가 정상으로 돌아오면, 변경 이력을 다시 적용해 동기화한다.
그림 12 Gizzard Migrations
④ Gizzard는 데이터 이전 방안을 제시할 수 있다. 데이터 노드가 A에서 B로 이전한다고 가정할 때 Replicate 샤드가 A와 B 사이에 위치하고 Writeonly는 B 앞에 위치해서 A의 데이터를 B로 복제하게 된다. Writeonly 샤드는 B가 사용 가능한 시점까지 유지되다가 B가 사용 가능한 시점이 되면 WriteOnly는 빠지고 Replicate가 동시에 A와 B에 데이터를 복제하며 동기화해 준다.
+ 고려사항 Gizzard는 동일 데이터를 동시에 변경하려면 데이터 충돌(Confliction)이 발생한다. 그래서 Gizzard는 데이터가 적용 순서를 보장하지 않기 때문에 모델링 시 반드시 이러한 점을 염두에 둬야 한다.
2) SPIDER for MySQL
+ 개요 SPIDER는 Kentoku SHIBA가 개발한 스토리지 엔진이다. MySQL의 파티셔닝 기능을 사용해 파티션마다 다른 서버로 데이터를 저장할 수 있게 한 구조이다. Sharding 기능이 가능한 스토리지 엔진이라고 할 수 있다. 물론 데이터가 저장된 서버가 다른 경우에도 조인할 수 있는 장점이 있다. 이러한 구조를 구현할 수 있었던 배경은 MySQL의 유연한 스토리지 엔진구조가 있었기 때문이다.
+ 아키텍처
그림 13 Spider for MySQL
Spider 는 위 그림처럼 테이블 링크를 통해 로컬의 MySQL 서버처럼 활용할 수 있는 구조이다. 내부적으로는 클러스터의 약점인 애플리케이션에서 구현하던 분산 환경에서의 조인과 트렌잭션 문제를 Spider가 해결해 준다. 더불어 Spider는 XA 트렌잭션과 테이블 파티셔닝을 지원한다. GPL 라이선스 정책을 갖고 있다. 여기에 병BR>+ 고려사항 ① SPIDER 테이블을 드롭해도 데이터 노드의 데이터는 사라지지 않는다. SPIDER은 FEDERATED 스토리지 엔진과 마찬가지를 생성하는 스토리지 엔진으로 테이블 DROP 때는 링크만 제거된다. 더불어 TRUNCATE 명령문은 원격 MySQL Server의 데이터를 모두 클리어해 버리므로 주의하자. ② MySQL Cluster처럼 Spider도 파티션을 전제로 한 스토리지 엔진이기 때문에 Distribution Awareness를 고려한 설계를 해줘야 한다. ③ 전체 텍스트 검색과 R-Tree 인덱스를 지원하지 못한다.
3) Spock Proxy
+ 개요 Spock Proxy는 MySQL Proxy를 바탕으로 제작된 샤딩 플랫폼이다. 데이터베이스들을 수평적 분할해 여러 샤드(shard)로 나눠줘 응용 프로그램들이 직면한 중요한 문제들을 해결해 줬고, 이로써 데이터베이스는 성능과 확장성을 쉽게 높일 수 있다. 주요 역할은 Proxy가 클라이언트로부터 전송되는 쿼리를 가로채 데이터가 분할된 기법에 따라 적절한 MySQL 서버에 쿼리를 전송한다. 이후 각 MySQL 서버로부터의 응답을 모아 일반 MySQL 결과인 것처럼 클라이언트로 다시 전송한다.
+ 아키텍처
그림 14 Spock Proxy
Spock proxy는 MySQL DB의 Table(universal_db)에 샤딩 규칙을 저장한다. 그래서 애플리케이션 서버로부터 전달받은 SQL을 파싱해, 이 SQL에 shard key가 있는지 파악한다. 만약 shard key가 있다면 universal_db에 기록된 기준에 따라 MySQL 인스턴스를 찾아 SQL을 전달한다. 이런 방식을 사용할 경우 SQL에 shard key와 관련한 정보를 기술할 필요가 없는 장점으로 인해 기존 애플리케이션을 그대로 이용할 수 있다.
+ MySQL Proxy와 다른 점 Spock Proxy는 MySQL Proxy에서 갈라진 것이다. 코드의 많은 부분이 변경되지 않았지만 기반 아키텍처가 다르다.
① MySQL Proxy는 최적화를 위해 Lua 스크립트 언어를 지원하지만, Spock Proxy는 그렇지 않다. 성능상의 이유로 C/C++를 활용했다. ② MySQL Proxy는 각 클라이언트가 개별 데이터베이스에 직접 인증하는 것을 허용한다. 이는 클라이언트가 proxy 작업에 앞서 최소 연결을 해야 하기 때문에 문제가 있는 방법이다. Spock Proxy는 클라이언트로부터 독립된 서버 연결을 하도록 설계됐다. ③ Spock Proxy는 클라이언트와 서버 연결을 분리해, 관리할 최소/최대 연결 크기를 허용한다. 시작 시에 proxy는 최소 연결 개 수만큼을 미리 연결해 놓는다. ④ 다중 서버 Send/Recv가 가능하다. 그래서 다수의 서버에 요청을 보내고, 이 결과들을 합치는 것 또한 가능하다.
+ 고려사항 Spock Proxy의 제약사항을 보면 쉽게 구현 단계에서 고려 사항들이 도출될 것이다 ① 데이터베이스들간의 조인이 불가능하다. ② 저장 프로시저와 트랜잭션 지원은 제한적이다. ③ 중첩 질의는 불가능하다. ④ SELECT에서 2개 테이블의 JOIN은 지원하지만, GROUP BY는 지원하지 않는다. ⑤ INSERT에서 칼럼명은 항상 표현돼야 한다. ⑥ MySQL 함수는 데이터들이 여러 파티션에 걸쳐 있는 경우 MAX, MIN, SUM, AVERAGE만 지원한다. ⑦ Spock Proxy는 read only (slave)와 read/write (master)를 구분하지 못한다. ⑧ auto_increment 값이 다르다.
5. 결론
MySQL은 다양한 방식의 스케일아웃을 지원하는 솔루션들이 있고, 지속적으로 개발?보완되고 있다. 중요한 건 우리가 용도에 적합한 솔루션들을 선택할 수 있는 혜안을 갖고 판단할 필요가 있다는 것이다. 비즈니스에 어느 정도 제약성도 있다는 점을 기획자들이 인지할 수 있게 지속적으로 커뮤니케이션 하는 활동도 필요하다. 거기에 DBA나 프로그래머들은 제약 사항 및 고려 사항들을 숙지하고 있어야 하며, 운용하면서 발생될 수 있는 문제점을 애플리케이션이든, 자체 미들웨어를 갖추든 보완하는 자세도 필요해 보인다. 트위터나 페이스북 등에서 행해지는 MySQL을 보완해 주는 미들웨어들을 유심히 살펴본다면 힌트를 얻을 수 있을 것이다.
[root@localhost ~]# /usr/bin/mysql -uroot mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.0.77 Source distribution
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> update user set password=password('P@ssw0rd') where user='root';
Query OK, 3 rows affected (0.00 sec)
Rows matched: 3 Changed: 3 Warnings: 0
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> quit
Bye
mysqld 재시작
이제 패스워드를 입력해야만 mysql을 사용할 수 있도록 하기 위해, mysqld를 재시작한다.
[root@localhost ~]# service mysqld restart
STOPPING server from pid file /var/run/mysqld/mysqld.pid
120229 13:08:54 mysqld ended
Stopping MySQL: [ OK ]
Starting MySQL: [ OK ]
[1]+ Done /usr/bin/mysqld_safe --skip-grant
→ 백그라운드로 실행 중이던 무인증 안전모드 mysqld 프로세스가 중지되고 정상모드 mysqld로 재시작되었다.
이동↑ERROR 1049 (42000): Unknown database 'mysql' 라고 나오면서 안들어 가지는 경우가 있을 수 있는데, mysql 설치 이후 한번도 root 패스워드를 지정하지 않은 상태이다. 이 때는 본 문서를 따르지 말고 service mysqld restart한다. 그러면 mysqladmin을 통한 패스워드 설정 방법이 나올 것이다.
MSSQL 에서는 배열을 처리할 수 없습니다. 따라서 다음과 같은 방식으로 우회하여 처리하는 방법이 있습니다. client 에서 comma 로 구분된 자료를 Stored Procedure 로 보내면 이 SP 에서는 콤마로 구분된 자료들을 하나씩 분리하여 원하는 기능에 넣어 사용하게 되는 방법입니다. 참조되시길...
CREATE PROCEDURE pro_array @DATA VARCHAR(1000) AS BEGIN
/*
- 최대 1000 자리수의 값을 받습니다. 이 길이는 조정 가능 - 콤마로 구분된 PK항목값 들을 UPDATE 구분에서 활용하는 예제입니다. */
WHILE CHARINDEX(',',@DATA)<>0 BEGIN UPDATE 테이블명 SET 항목명 = '선택' WHERE PK항목명 = SUBSTRING(@DATA,1,CHARINDEX(',',@DATA)-1)
SET @DATA=SUBSTRING(@DATA,CHARINDEX(',',@DATA)+1,LEN(@DATA))
IF CHARINDEX(',',@DATA)=0 BEGIN UPDATE 테이블명 SET 항목명 = '선택' WHERE PK항목명 = SUBSTRING(@DATA,1,LEN(@DATA)) END END END
mysql>
show
processlist;
+---------+------+-----------+-------+---------+------+-------+------------------+
|
Id | User | Host | db | Command | Time | State | Info
|
+---------+------+-----------+-------+---------+------+-------+------------------+
|
1603286 | root | localhost | NULL | Query | 0 | NULL | show processlist
|
+---------+------+-----------+-------+---------+------+-------+------------------+
2
rows in set (0.00 sec)
Id : 프로세스 아이디 MySQL 이 관리하는 스레드 번호。
User : 스레드에 접속하고 있는 MySQL 유저명
Host : 유저가 접속하고 있는 호스트명 , IP 어드레스
Command : 스레드의 현재 커맨드 상태 .
Time : 프로세스가 현재 커맨드상태에서 동작 시간
State : 스레드의 상태에 대해 사람이 읽을 수 있는 형태의 정보
Info : 현 실행되고 있는 SQL .
"SHOW PROCESSLIST" 최대 100자까지 표시
전부 표시하려면 "SHOW FULL PROCESSLIST"
int mysql_insert_id
( [resource link_identifier] )
이전의 INSERT 질의로부터 AUTO_INCREMENT 컬럼에 의해 생성된 ID를
반환한다.
인수 목록
link_identifier
The MySQL connection. If the link identifier is
not specified, the last link opened by mysql_connect() is assumed. If no such link is found, it will try to
create one as if mysql_connect() was called with no arguments. If by chance no
connection is found or established, an E_WARNING
level warning is generated.
반환값
성공하면 이전의 INSERT 질의에 의한 AUTO_INCREMENT 컬럼으로부터
생성된 ID를, 이전 질의로부터 AUTO_INCREMENT 값이 생성되지 않았다면, 0을, MySQL 접속이
되지 않은 상태였다면 FALSE를
반환한다.
예제
예 1. mysql_insert_id() 예제
<?php
$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb');
mysql_query("INSERT INTO mytable (product) values ('kossu')");
printf("Last inserted record has id %d\n", mysql_insert_id());
?>
Notes
경고
mysql_insert_id()는 원시(native) MySQL C API 함수인 mysql_insert_id()의 long형태의 반환값을
PHP의 int로 변환한다.
AUTO_INCREMENT 컬럼이 BIGINT이면, mysql_insert_id()에 의해 반환되는 값은 잘못될 것이다. 이경우, MySQL SQL 내부 함수인 LAST_INSERT_ID()를 사용하면 된다.
참고: mysql_insert_id()는 최근 수행한 질의에 대해서 동작하기 때문에, 생성된 값은 질의 직후에 mysql_insert_id()를 호출해야 된다.
참고: MySQL SQL 함수인 LAST_INSERT_ID()는 가장 최근에 생성된 AUTO_INCREMENT 값을 담고 있으며, 질의 간에 지워지지는 않는다.
- DAYOFMONTH(date) : 해당 날짜의 일을 반환한다. 결과값은 1 에서 31 까지이다.
- 예 : select DAYOFMONTH('1998-02-03');
- HOUR(time) : 해당날짜의 시간을 반환한다. 결과값은 0 에서 23 이다.
- 예 : select HOUR('10:05:03');
- MINUTE(time) : 해당날짜의 분을 반환한다. 결과값은 0 에서 59 이다.
- 예 : select MINUTE('98-02-03 10:05:03');
- SECOND(time) : 해당날짜의 초를 반환한다. 결과값은 0 에서 59 이다.
- 예 : select SECOND('10:05:03');
- DAYNAME(date) : 해당 날짜의 요일 이름을 반환한다. 일요일은 'Sunday' 이다.
- 예 : select DAYNAME("1998-02-05");
- MONTHNAME(date) : 해당 날짜의 월 이름을 반환한다. 2월은 'February' 이다.
- 예 : select MONTHNAME("1998-02-05");
- QUARTER(date) : 해당 날짜의 분기를 반환한다. 결과값은 1 에서 4 이다.
- WEEK(date,first) : 1월 1일부터 해당날가지의 주 수를 반환한다. 주의 시작을 일요일부터 할경우는 두번째 인자를 0, 월요일부터 시작할 경우는 1 을 넣는다. 결과값은 1 에서 52 이다.
- 예 : select WEEK('1998-02-20',1);
- PERIOD_ADD(P,N) : P (형식은 YYMM 또는 YYYYMM 이어야 한다.) 에 N 만큼의 달 수를 더한값을 반환한다. 주의할것은 두번째 인자는 숫자라는 것이다.
- 예 : select PERIOD_ADD(9801,2);
- PERIOD_DIFF(P1,P2) : 두개의 인자 사이의 달 수를 반환한다. 두개의 인자 모두 형식은 YYMM 또는 YYYYMM 이어야 한다.
- DATE_ADD(date,INTERVAL expr type) : 날짜를 더한 날짜를 반환한다.
- DATE_SUB(date,INTERVAL expr type) : 날짜를 뺀 날짜를 반환한다.
- ADDDATE(date,INTERVAL expr type) : DATE_ADD(date,INTERVAL expr type) 와 동일하다.
- SUBDATE(date,INTERVAL expr type) : DATE_SUB(date,INTERVAL expr type) 와 동일하다.
- EXTRACT(type FROM date) : 날짜에서 해당 부분을 추출한다.
- 예 : SELECT DATE_ADD("1997-12-31 23:59:59", INTERVAL 1 SECOND);
SELECT DATE_ADD("1997-12-31 23:59:59", INTERVAL 1 DAY);
SELECT DATE_ADD("1997-12-31 23:59:59", INTERVAL "1:1" MINUTE_SECOND);
SELECT DATE_SUB("1998-01-01 00:00:00", INTERVAL "1 1:1:1" DAY_SECOND);
SELECT DATE_ADD("1998-01-01 00:00:00", INTERVAL "-1 10" DAY_HOUR);
SELECT DATE_SUB("1998-01-02", INTERVAL 31 DAY);
SELECT EXTRACT(YEAR FROM "1999-07-02");
SELECT EXTRACT(YEAR_MONTH FROM "1999-07-02 01:02:03");
SELECT EXTRACT(DAY_MINUTE FROM "1999-07-02 01:02:03");
- 참고 : type 에 사용되는 키워드는 SECOND, MINUTE, HOUR, DAY, MONTH, YEAR, MINUTE_SECOND, HOUR_MINUTE, DAY_HOUR, YEAR_MONTH, HOUR_SECOND, DAY_MINUTE, DAY_SECOND 이다.
- 주의 : 계산한 달의 날수가 작을 경우는 해당달의 마지막 날을 반환한다. 예를 들어 select DATE_ADD('1998-01-30', Interval 1 month); 의 경우 1998-02-28 을 반환한다.
- TO_DAYS(date) : 0 년 부터의 날짜수를 반환한다. 이 함수는 1582 이전 날에 대해서는 계산하지 않는다.
- 예 : select TO_DAYS(950501);
- FROM_DAYS(N) : 해당 숫자만큼의 날짜를 반환한다. 이 함수는 1582 이전 날에 대해서는 계산하지 않는다.
- 예 : select FROM_DAYS(729669);
- DATE_FORMAT(date,format) : 날짜를 해당 형식의 문자열로 변환하여 반환한다.
- 예 : select DATE_FORMAT('1997-10-04 22:23:00', '%W %M %Y');
select DATE_FORMAT('1997-10-04 22:23:00', '%H:%i:%s');
select DATE_FORMAT('1997-10-04 22:23:00', '%D %y %a %d %m %b %j');
select DATE_FORMAT('1997-10-04 22:23:00', '%H %k %I %r %T %S %w');
- 참고 : 형식은 다음과 같다. %M (달 이름), %W (요일 이름), %Y (YYYY 형식의 년도), %y (YY 형식의 년도), %a (요일 이름의 약자), %d (DD 형식의 날짜), %e (D 형식의 날짜), %m (MM 형식의 날짜), %c (M 형식의 날짜), %H (HH 형식의 시간, 24시간 형식), %k (H 형식의 시간, 24시간 형식), %h (HH 형식의 시간, 12시간 형식), %i (MM 형식의 분), %p (AM 또는 PM)
- TIME_FORMAT(time,format) : DATE_FORMAT(date,format) 과 같은 방식으로 사용할수 있으나 날 이상의 것에 대해서는 NULL 이나 0 을 반환한다.
- CURDATE() : 현재날짜를 반환한다. 숫자와 연산을 할경우 숫자로 변환된다. 형식은 'YYYY-MM-DD' 또는 YYYYMMDD 이다.
- 예 : select CURDATE();
select CURDATE() + 0;
- CURTIME() : 현재시간을 반환한다. 숫자와 연산을 할경우 숫자로 변환된다. 형식은 'HH:MM:SS' 또는 HHMMSS 이다.
- 예 : select CURTIME();
select CURTIME() + 0;
- SYSDATE() : 현재날짜시간을 반환한다. 숫자와 연산을 할경우 숫자로 변환된다. 형식은 'YYYY-MM-DD HH:MM:SS' 또는 YYYYMMDDHHMMSS 이다.
- 예 : select NOW();
select NOW() + 0;
- NOW() : SYSDATE() 와 동일하다.
- UNIX_TIMESTAMP() : '1970-01-01 00:00:00' 부터의 초를 반환한다. 인자가 주어질 경우는 해당 날짜에 대한 유닉스 시간을 반환한다.
- 예 : select UNIX_TIMESTAMP();
select UNIX_TIMESTAMP('1997-10-04 22:23:00');