이것이 MySQL이다
이제 처음부터 끝까지 직접 만들어서 운영중인 서비스가 벌써 운영 9개월차를 맞이하고 있다. 아무래도 초기 서비스이기에 최초 런칭 이후에도 수없이 많은 A/B 테스트들이 있었고 그만큼 많은 변화들이 있었다.
이번 업데이트에서는 지금까지 모든 유저에게 쌓여왔던 데이터들을 새로운 테이블로 마이그레이션 하는 작업이 포함되었는데, 그렇다 보니 여러모로 Mysql 을 아직 잘 모르고 있구나, 하는 부족함이 느껴졌었다. 그래서 이번 기회에 Mysql 관련 읽으면 좋은 책을 찬찬히 읽고 알았던 내용들, 몰랐던 내용들을 찬찬히 정리해보는 시간을 갖으려 한다.
원페이지에 정리하느라 다소 긴 글이 되었지만, Mysql 관련해서 막힐 때 한 곳에서 cmd + F
명령어로 쉽게 찾아보고 싶어서 일부러 한 페이지에 정리를 해두었다.
Mysql
Oracle 사에서 제작한 DBMS 소프트웨어로 오픈소스임
Workbench
수행시간이 긴 쿼리를 수행할 때에는 edit > preference 에서 timeout interval 관련 설정을 0으로 두면 시간제한이 없어진다.
모델링
현실 세계 -> DBMS 의 데이터베이스 개체로 옮기는 과정
모델링하는 과정 살펴보기 - 쇼핑몰 (p140)
고객
구매기록
권한
사용자 생성, 권한부여, 삭제
데이터타입
숫자
bit, tinyint, smallint, mediumint, int, bigint
unsigned 예약어를 붙여주어 양수만 표현할 수 있다.
사라진 음수범위만큼 양수범위의 표현범위가 늘어난다.
float, double, decimal
decimal : 정확한 값을 표현. ex) decimal(9,2)
float, double : 근사치를 표현.
문자
char, varchar
char : 고정 자리수
insert, update 시에 더 좋은 성능을 발휘한다.
varchar : 가변 자리수
binary, barbinary
tinytext, text, mediumtext, longtext
텍스트 데이터
tinyblob, blob, mediumblob, longblob
사진, 음성, 파일 등의 이진 데이터
enum
set
일부 DBMS 에서는 한글(유니코드 2byte)과 영어(영문자 1byte)에 메모리를 다르게 할당하여, 보통 영어는 varchar, char 를 사용하고 한글은 nvarchar, nchar를 할당하여 테이블을 설계한다.
하지만 mysql 에서는 varchar(10) 의 경우, 영어나 한글 모두 10자까지만 허용이 되도록 되어있기 때문에 mysql 에서는 굳이 nvarchar, nchar 데이터타입을 사용할 필요가 없다.
날짜와 시간
date
time
datetime
timestamp
year
기타데이터
geometry : 공간데이터 형식. 선, 점, 다각형과 같은 공간 데이터 개체를 저장하고 조작
json : json 문서를 저장
형변환
명시적인 형변환
cast(), convert()
두 함수는 형식만 다르고 거의 같은 역할을 한다
암시적인 형변환
'100' + '200' = 300 : 문자열 -> 숫자
concat('100', '200') = 100200 : 문자열+문자열
concat(100, '200') = 100200 : 정수 -> 문자열
데이터
데이터로 NULL 입력시, char 타입에서는 공간 전체를 차지하는 반면 varchar 타입에서는 공간을 사용하지 않는다. 따라서 NULL 값 입력이 많은 컬럼은 varchar 타입으로 지정하는 것이 유리하다.
DDL
데이터베이스 개체 (데이터베이스, 테이블, 뷰, 인덱스, 트리거, 프로시저 등) 를 생성, 삭제, 변경하는 언어
create, alter, drop
DDL 은 트랜잭션이 적용되지 않는다. 롤백불가함
테이블 복사
CREATE TABLE ... SELECT
FK 등의 제약조건은 복사되지 않고 테이블 구조와 내부 데이터만 복사된다
ROLLUP 으로 총합, 중간합계
DML
데이터를 조작하는 언어
select, insert, update, delete
transaction 이 발생한다.
DCL
사용자에게 어떤 권한을 부여하거나 빼앗을 때 사용하는 구문
grant, revoke, deny 등
SELECT
INSERT
데이터의 삽입
insert into table values (datas);
insert into (column names) values (datas)
auto_increment
자동증가
시작점 다시 초기화하기
alter table <table name> auto_increment=?;
증가폭 커스텀하기 (default : 1)\
set @@auto_increment=3;
대량데이터 삽입
insert into <table> select ... ;
ignore
insert 시에 해당 구문이 오류가 나도 다음 구문이 실행된다.
insert ignore into member values ();
on duplicate key update
insert 구문 실행 시, 키가 중복되면 데이터를 업데이트 하도록 한다.
insert into member values () on duplicate key update name=?, addr=?;
UPDATE
데이터의 수정
update user set name = ?, phone_number = ? where 조건;
DELETE
delete from 테이블 where 조건
실습(p225) : 대용량 테이블 삭제하기
아래의 세 개의 쿼리의 수행시간 비교하기
delete from user;
drop table user;
truncate table user;
결과
delete > truncate > drop 순으로 시간이 오래 걸렸다.
delete : DML 이기 때문에 transaction 이 발생함.
truncate, drop : DDL 이기 때문에 로그 기록하지 않아서 수행시간이 엄청 빠름
따라서 테이블이 필요없는 경우 drop, 테이블이 필요한 경우 truncate 로 전체 데이터를 삭제하는 편이 좋다.
with and CTE
뷰, 파생테이블, 임시테이블 등을 간결하게 표현하기 위해 사용하는 구문
with CTE_테이블이름(열이름) AS ( 쿼리문 ) select 열 이름 from CTE_테이블이름;
즉 서브쿼리 등을 쓸 때 복잡한 구문을 간결하게 표현해주는 장점이 있다.
중복적으로 사용이 가능하다
vs. View
view : 계속 남아있어서 다른 구문에서도 사용될 수 있다.
cte : 해당 구문이 실행되면 소멸된다. 재사용 불가하다.
SQL 문에 조건걸기
where
부등호 관계연산자 사용
between and
in()
like '%word%'
Any, All, Some 과 서브쿼리
서브쿼리를 이용해서 조건절 데이터를 넣을 때, 사용할 수 있는 키워드들
ANY = SOME : > ANY
여러개의 결과 중 하나만 만족해도 됨
select * from usertbl where heigh > any (select height from usertbl from addr = '경남');
결과 : 173 혹은 170보다 큰 경우가 모두 출력됨
ALL : > ALL
여러개의 결과를 모두 만족시켜야함
select * from usertbl where heigh > all (select height from usertbl from addr = '경남');
결과 : 173보다 크고, 170보다 큰 경우가 모두 출력됨
= ANY()
=in ()
정렬 - Order by
ASC, DESC
위치 : 항상 SELECT 문의 제일 마지막에 위치해야한다.
mysql 성능을 떨어뜨릴 위험이 있으므로 꼭 필요한 경우가 아니라면 사용하지 않는게 좋다.
중복제거 - DiSTINCT
출력 개수를 제한 - LIMIT
limit n : n개만 출력
limit 시작, 개수 : limit 0, 5
limit 개수 offset 시작 : limit 5 offset 0
그룹함수 - GROUP BY, HAVING, 그리고 집계함수
group 함수(집계함수)가 쓰인 쿼리에 조건을 걸려면 where 가 아니라 having 을 이용한다.
집계함수 종류
sum()
avg()
min()
max()
count()
count(distinct)
stdev() : 표준편차
var_samp() : 분산
example
select user_id, sum(amount) from users group by user_id;
최대키, 최소키를 가진 사람 이름과 함께 출력하기
select name, height from user where height = (select max(height) from user) or height = (select min(height) from user);
Schema
데이터베이스/스키마 선택하기
현재 데이터베이스/스키마 내부의 모든 테이블 조회
데이터베이스 개체 이름 규칙
64자 제한
소문자 기준. 대문자도 소문자로 인식됨
linux 에서는 반드시 소문자로 사용해야함
예약서 사용불가 : ex) select
자주쓰이는 함수들
제어흐름
IF(수식, 참, 거짓)
IFNULL(수식1, 수식2) : null 이면 수식1, null이 아니면 수식2
NULLIF(수식1, 수식2) : 수식1 = 수식2 면 null, 다르면 수식1
case ... when ... else ... end as 'alias'
문자열함수
ASCII(아스키코드) = 숫자
CHAR(숫자) = 아스키코드 문자
length(문자열)
concat(문자열, 문자열, 문자열)
concat_ws(구분자, 문자열, 문자열) : 구분자와 함께 연결해줌
SQL 프로그래밍
변수 사용하기
SET @변수
전역변수처럼 사용
워크밴치 종료후에는 소멸된다.
예시
set @변수명 = ?; select 변수명;
스토어드 프로시저 or 함수 내부
declare 로 변수 선언 후 내부에서는 그냥 변수명만 사용함. 지역변수 같은 느낌
Prepare + execute 으로 limit 구문에 변수 사용이 가능하다. (p268 참고)
테이블과 뷰 | Table and View
테이블
Mysql 5.0 부터 테이블 압축 기능이 추가되었다.
압축 테이블에 데이터를 입력하면 시간이 그냥 테이블의 2배정도 소용된다.
하지만 테이블 상태를 보면 평균 행 길이나 데이터 길이가 2배정도 작다.
테이블 생성할때만 지정하면 그 이후로는 일반 테이블과 사용방법이 같다.
대용량 데이터가 가득한 테이블에 적용하면 유리할 듯
임시테이블 Temporary table 이라는 것이 있다.
mysql 세션 내에서만 존재하므로 워크벤치 세션 창을 닫으면 사라진다.
기존 일반적인 테이블과 같은 이름을 사용할 수 있다.
하지만 해당 이름으로 데이터를 조회할 경우, 임시테이블이 우선순위를 갖게되어 기존 테이블 데이터는 조회되지 않는다.
활용 아이디어
데이터 마이그레이션 처럼 임시로 테이블이 존재해야하는 경우들에서 종종 사용할 수 있을 것 같다.
뷰 view
테이블과 동일하게 생각하고 접근해도 된다. 비슷한 개념. 테이블에서 필요한/자주쓰이는 컬럼만 뽑아놓은 엑기스 같은 느낌
뷰는 보통 읽기 전용으로 많이 사용됨. 하지만 수정도 가능은 함! → 별로 추천하지 않음
테이블, 뷰 두 군데서 데이터를 수정할 수 있다면 혼란스러울 수 있다.
장점
보안에 도움이 된다. 개인정보인 출생년도, 연락처 등 민감한 정보는 제외하고 조회할 수 있다.
매번 사용되는 특정 컬럼을 뽑는 복잡한 쿼리를 단순화할 수 있다.
테이블 스페이스
각 테이블이 실제 저장되는 물리적인 공간을 의미함
기본적으로는 모든 테이블이 시스템 테이블스페이스에 저장됨
대용량 테이블의 경우 별도의 테이블스페이스에 저장하는 것이 성능에 효과적이다.
인덱스 | Index
개념
데이터를 좀 더 빠르게 찾을 수 있도록 해주는 도구
반대개념 : 전체 테이블 검색 full table scan
주의할 점
불필요한 인덱스를 만들 경우에는 용량만 더 차지하고 오히려 검색속도가 느려진다.
장점
검색속도 향상
쿼리의 부하가 줄어서 전체적인 시스템 성능향상 가능
단점
데이터베이스의 10% 정도 크기의 추가공간이 필요하다.
처음 인덱스 생성시 시간 소요가 된다.
변경작업이 자주 일어날 경우에는 오히려 성능이 많이 나빠질 수 있다.
종류
클러스터형 : 영어사전
테이블 당 1개 생성 가능
인덱스로 지정한 열에 맞춰서 자동 정렬한다.
보조 : 책 뒤의 찾아보기
테이블 당 여러개 생성 가능
PK, Unique 에는 자동으로 인덱스가 설정됨
PK
,Unique + NotNull
에는 자동으로 클러스터형 인덱스가 설정된다.Unique
에는 자동으로 보조 인덱스가 설정된다.PK
vsUnique + NotNull
: PK 우선적으로 클러스터형 인덱스가 설정됨PK 지정한 열로 데이터가 오름차순으로 정렬된다.
주의할 점
신규로 생성할 때 인덱스가 적용되는 건 시간소요가 적다.
기존 운영되고 있는 테이블에 PK 나 Unique 키를 지정해서 인덱스를 지정하는 것은 시간소요가 클 수 있으니 주의해야한다.
B-Tree 구조를 갖는다. (p384)
균형 잡힌 트리 : 노드
Mysql 에서는 노드 대신 페이지라는 개념을 사용함. 한 페이지당 16kb 저장가능.
인덱스를 구성할 때 B-tree 구조를 갖는다.
검색시 뛰어난 성능 발휘 - 검색 대상을 효과적으로 좁힌다.
페이지 분할
INSERT, UPDATE, DELETE 등 데이터의 수정이 잦은 테이블에서는 오히려 역효과 발생 가능
페이지 분할이 일어나기 때문임!
생성과 삭제
CREATE INDEX
DROP INDEX
삭제 시에는 보조 → 클러스터 순서로
PK 에 설정된 인덱스는 Alter 문으로만 삭제가 가능하다.
성능비교 (p394)
보통의 경우 클러스터형 인덱스 > 보조 인덱스
클러스터형 페이지 구조
루트 페이지
리프 페이지 = 데이터페이지
보조 인덱스 페이지 구조
루트 페이지
리프 페이지 : 데이터 페이지의 주소값
데이터페이지 (heap 영역)
테이터 읽기 / 검색속도
클러스터형 > 보조
데이터 입력 / 수정 / 삭제
보조 > 클러스터형
보조 인덱스는 정렬을 하지 않기 때문에 데이터 수정시에 더 유리
클러스터형 인덱스
인덱스 생성 시 데이터 페이지 전체가 다시 정렬됨 → 대용량 데이터일 경우 부하가 심할 수 있으니 주의
인덱스 자체의 리프 페이지 = 데이터 : 인덱스 자체에 데이터가 포함되어있다.
보조 인덱스
데이터 페이지는 그대로 두고 별도의 페이지에서 인덱스를 구성함
리프 페이지 = 데이터가 위치하는 주소값
한 테이블 당 여러개 생성 가능하지만 남용할 경우 성능 저하 심각
혼합해서 사용하기
주의할 점
데이터의 종류가 적은 열에는 사용하지 않는게 나을 수 있다.
프로시저 | Stored Program - Procedures
Mysql 에서 제공하는 프로그래밍 기능
매개변수 사용 가능, 호출은 CALL 로
특징 / 장점
Mysql 성능을 향상시킬 수 있다.
긴 쿼리를 서버 → DB 로 전달하지 않고 미리 생성된 프로시저를 호출하는 것만으로도 충분히 큰 성능향상에 도움이 된다.
Mysql 은 호출될때마다 컴파일 되기 때문에 그 효과가 크지는 않지만, 다른 DBMS 는 1회 호출 때만 컴파일 되고 이후에는 메모리에 로딩되어 호출되므로 그 효과가 상당하다.
유지관리가 편하다
모듈식 프로그래밍이 가능하다.
보안을 강화할 수 있다.
테이블에 별도로 접근권한을 주지않고 프로시저에만 줄 수 있다.
필요한 정보만 조회하는 쿼리를 미리 프로시저로 만들어두면 제한된 정보만 노출할 수 있다.
함수 | Stored Program - Function
함수는 반환하는 값이 반드시 있다.
프로시저와의 차이점
프로시저의 파라미터와 달리 IN, OUT 을 사용할 수 없다. 모두 입력 파라미터로 사용된다.
RETURNS 문으로 반환할 데이터 형식을 정하고, RETURN 문으로 하나의 값을 반환해야한다.
프로시저가 CALL 로 호출되는 것에 반해, 함수는 SELECT 문장 안에서 호출된다.
프로시저에서는 SELECT 문을 사용할 수 있지만, 함수 내에서는 집합결과를 반환하는 SELECT 를 사용할 수 없다.
프로시저는 여러 SQL 문이나 숫자계산 등의 다양한 용도로 사용되지만, 함수는 어떤 계산을 통해서 하나의 값을 반환하는데 주로 사용된다.
커서 | Stored Program - Cursor
커서는 일반 프로그래밍의 파일처리와 비슷한 방법을 제공한다.
프로세스
파일을 연다
처음 데이터를 읽는다.
파일의 끝까지 반복한다.
파일을 닫는다.
트리거 | Stored Program - Trigger
트리거는 테이블의 DML 문이 작동하면 자동으로 실행되도록 설정한다.
쉽게 말하자면 테이블에 부착되는 프로그램 코드
부착된 테이블에 이벤트가 발생하면 자동으로 실행된다.
따로 직접 실행은 불가하며 오직 이벤트가 발생할 때에만 동작한다.
사용사례
A 테이블에서 기록 삭제전, B 테이블로 마지막 기록을 옮겨적어두면 나중에 A 테이블에서의 기록이 문제가 되어 확인이 필요해도 B테이블에서 확인할 수 있다.
종류
AFTER
해당 작업 후에 동작
BEFORE
해당 작업 전에 동작
DML 에만 동작한다.
DELETE 과 유사하게 Truncate 문이 사용되지만, TRUNCATE 시에는 트리거가 동작하지 않는다.
트리거가 생성하는 임시 테이블
NEW
INSERT, UPDATE 시에 변경할 새로운 데이터를 잠깐 저장해놓는 테이블
이 테이블을 조작하면 입력되는 새로운 값을 다른 값으로 대치시킬 수 있다.
OLD
DELETE 와 UPDATE 수행 전에 예전 값이 저장된다.
입력될 새로운 데이터는 NEW, 예전 데이터는 OLD 를 참고하면 된다.
BEFORE 트리거의 사용
테이블 변경이 가해지기 전에 작동되는 트리거
미리 해당 트리거를 부착해놓으면 입력될 데이터 값을 미리 확인해서 문제가 있을 경우에 다른 값으로 변경시킬 수 있다.
기타 트리거에 관한 내용
다중 트리거
한 테이블에 동일한 트리거가 여러개 부착되어있는 것
예 ) AFTER INSERT 트리거가 2개이상 부착되어있을 수 있다.
중첩 트리거
트리거가 또 다른 트리거를 작동하는 것
고객 → 구매 → 물품
시스템 성능에 좋지 않은 영향을 미칠 수 있다.
연결된 트리거 중 하나가 실패하면 전체가 롤백되기 때문임
작동순서
하나의 테이블에 여러개의 트리거가 부착되어있다면 작동 순서를 정할 수 있다.
전체 텍스트 검색
긴 문자의 텍스트 데이터를 빠르게 검색하기 위한 기능
전체 텍스트 인덱스는 신문기사와 같이 텍스트로 이루어진 문자열 데이터의 내용을 가지고 생성한 인덱스를 말한다.
일반 SELECT 문의 WHERE 절에 MATCH() AGAINST() 를 사용하면 된다.
인덱스 생성
Inno DB, MyISAM 테이블만 지원한다.
char, varchar, text 의 열에만 생성이 가능하다.
인덱스 힌트의 사용이 일부 제한된다.
여러개 열에 full text 인덱스를 지정할 수 있다.
중지단어
검색에서 무시할만한 단어는 아예 인덱스로 지정하지 않는다.
예) 이번, 아주, 모두, 꼭
쿼리
where 절에서 MATCH() AGAINST() 를 사용한다.
자연어 검색 지원 : IN NATURAL LANGUAGE MODE
단어가 정확한 것을 검색해준다.
불린모드 검색
IN BOOLEAN MODE
정확히 그 단어만 포함된 내용을 검색한다.
파티션
파티션은 대량의 테이블을 물리적으로 여러 개의 테이블로 쪼개는 것을 말한다.
파티션을 나눈다고 해서 무조건 효율적인 것은 아니다. 데이터의 분포 특정이나 자주 사용되는 쿼리문에 따라서 효율에 차이가 발생한다.
사용예시
10년간의 데이터가 저장되었을 경우
과거의 기록은 주로 조회용
작년 이전 - 올해 데이터 서로 다른 파티션으로 저장
월별로 업데이트가 잦은 데이터 : 월별로 파티션 테이블 구성
테이블 생성시, 파티션 키를 함께 지정
데이터 입력시에 지정된 파티션 키에 의해서 데이터가 각각의 파티션에 입력된다.
파티션 삭제시에는 파티션 데이터도 같이 삭제되므로 주의해야한다.
파티션 데이터를 모두 삭제할 때에는 아예 파티션을 삭제하는게 더 효율적이다.
주의사항
파티션 적용된 테이블에는 외래키를 적용할 수 없다.
프로시저, 스토어드 함수, 사용자 변수 등을 파티션 함수나 식에 사용할 수 없다.
임시 테이블은 파티션 기능을 사용할 수 없다.
파티션 키에는 일부 함수만 사용할 수 있다.
개순ㄴ 최대 8129개까지만 지원됨
레인지 파티션은 숫자형의 연속된 범위를 사용하고
리스트 파티션은 숫자 혹은 문자형의 연속되지 않은 하나하나씩 파티션 키 값을 지정한다.
리스트 파티션에서는 MAXVALUE 를 사용할 수 없다.
공간데이터
GIS 는 지도와 텍스트 정보를 컴퓨터에서 활용하는 분야이다.
Mysql 5.0 부터 공간데이터를 위한 Geometry 데이터 형식을 지원한다.
공간 데이터 입력은 ST_GeomFromTex() 함수를 사용하여 입력할 수 있다.
ST_ 로 시작하는 다양한 공간 데이터 형식의 함수를 제공한다.
Last updated