반응형

 

 

Mysql 책중에서 가장 많이 알려진 

 

Real Mysql의 저자 강의가 나왔다고 한다.

인프런이라는 곳에서 확인해볼 수 있는데

Real mysql 8.0 이 책이 2권인데 거기에 맞춰서 강의도 2개로 나눠진 거 같다.

#Real MySQL 시즌 1 - Part 1

 

Real MySQL 시즌 1 - Part 1 강의 | 이성욱 - 인프런

이성욱 | MySQL의 핵심적인 기능들을 살펴보고, 실무에 효과적으로 활용하는 방법을 배울 수 있습니다. 또한, 오랫동안 관성적으로 사용하며 무심코 지나쳤던 중요한 부분들을 새롭게 이해하고,

www.inflearn.com

 

 

#강의 내용 

1.CHAR vs VARCHAR
2.VARCHAR vs TEXT
3.COUNT(*) & COUNT(DISTINCT) 튜닝
4.페이징 쿼리 작성
5.Stored Function
6.Lateral Derived Table
7.SELECT ... FOR UPDATE
8.Generated 컬럼 및 함수 기반 인덱스
9.에러 핸들링
10.LEFT JOIN 주의사항 및 튜닝
11.Prepared Statement
12.SQL 문장의 가독성 향상

#강의 시간
(충 3시간 29분)

#Real MySQL 시즌 1 - Part 2

 

Real MySQL 시즌 1 - Part 2 강의 | 백은빈 - 인프런

백은빈 | MySQL의 핵심적인 기능들을 살펴보고, 실무에 효과적으로 활용하는 방법을 배울 수 있습니다. 또한, 오랫동안 관성적으로 사용하며 무심코 지나쳤던 중요한 부분들을 새롭게 이해하고,

www.inflearn.com

 

 


#강의 내용 


1.콜레이션
2.UUID 사용 주의사항
3.풀스캔 쿼리 패턴 및 튜닝
4.COUNT(*) vs COUNT(column)
5.SELECT ... FOR UPDATE [ NOWAIT | SKIP LOCKED ]
6.UNION vs UNION ALL
7.JSON 타입 활용
8.데드락
9.JOIN UPDATE & JOIN DELETE
10.커넥션 관리
11.테이블 파티셔닝
12.DBMS 활용 (배치 처리 주의사항)

#강의 시간 

(총 3시간 59분)

책에 있는 내용을 설명해주는 강의 같은데

강의시간도 길지 않아서 부담없이 들어볼만 할 것 같다.

 



Mysql이나 MariaDB를 다루는 DBA라면 

한번쯤은 들어야하는 강의가 되지 않을까 싶다.

끝.

반응형
블로그 이미지

dung beetle

취미는 데이터 수집 직업은 MYSQL과 함께 일하는 DBA의 소소한 일상 이야기

,
반응형

왜  binary 설치인가?

- yum install이나 apt-get, rpm 등 설치는 설치할 때는 편할지 모르지만 관리가 힘들다.

binary 설치하게 되면 초기 설정만 잘 해주며 폴더별로 관리하기 편하고 백업 및 마이그레이션 작업도 수월하기에 상용 서비스 DB를 설치할 때는 binary로 설치하는 것을 추천한다.

 

사전 확인 작업

 

1. 장비 하드웨어 스팩확인

1-1) CPU 확인

#물리 CPU 개수

 [root@ ~]# grep "physical id" /proc/cpuinfo | sort -u | wc -l
2

 

 

#CPU당 물리 코어 수

[root@ ~]# grep 'cpu cores' /proc/cpuinfo | tail -1
cpu cores : 6

 

#CPU 코어 전체개수

 [root@ ~]# grep -c processor /proc/cpuinfo
24

 

-> 맞는지 한번 계산해본다.

1 core * 6 * 2(가상 하이퍼스레딩) = 12

1 core * 6 * 2(가상 하이퍼스레딩) = 12

=> 총 24 코어

 

1-2) 메모리 확인

[root@~]# free -m
             total       used       free     shared    buffers     cached
Mem:         32079      29966       2113          1        563       5460
-/+ buffers/cache:      23942       8137
Swap:        15999       3360      12639

=> 32G

 

2. OS 스팩 확인

2-1) 설치 OS version 확인

[test-db@ ~]$ cat /etc/centos-release
CentOS release 6.10 (Final)

 

2-2) glibc 버전 확인

[test-db@ ~]$ getconf -a | grep libc
GNU_LIBC_VERSION                   glibc 2.12

 

3. 파일시스템 확인

[test-db@ ~]$ df -Th
Filesystem           Type   Size  Used Avail Use% Mounted on
...
/dev/sdb1            ext4   1.1T  126G  919G  12% /data
/dev/sda8            ext4   212G   95G  107G  48% /backup

 

DB를 설치할 경로(/data)에 파일시스템을 확인

제일 좋은 선택은 대용량이라면 XFS라고 하는데 실제로 마운트 옵션을 둘다 제대로 주고 테스트해본 바는 EXT4가 쿼리수행시간이 일정하게 들어오고 

XFS는 빠를땐 빠르고 느릴땐 느리고..뭔가 들쭉날쭉했다.

--> 실제 상용서비스는 마운트옵션은 EXT4로 사용중이다.

 

ex)

테스트 DB spec은 mysql 5.7.19 / SSD / 쿼리캐시 off/ 데이터는 100G / 테이블 300개

/ 테스트쿼리(OLAP) 수행시간 30초 / 조인테이블 6개 /인덱스 타고 풀스캔 없음

 

 4. 마운트옵션 확인

vi /etc/fstab
...
UUID=xxxxxxx-xxxd-4xx0-axx6-6xxxxxfxx5b1 /data                    ext4    defaults        1 2

 

 

defaults는 성능이 좋지 않다. 

아래처럼 변경하면 좀 더 나은 성능을 기대할 수 있다.

ext4 ---->         rw,noatime,nodiratime,nobarrier,data=ordered
xfs  ---->         rw, noatime,nodiratime,nobarrier,logbufs=8,logbsize=32k

 

5. 오픈파일 개수 설정

vi /etc/security/limits.conf

# mysql setting
mysql         soft    nproc         65535
mysql         hard   nproc         65535
mysql         soft    nofile         65535
mysql         hard   nofile         65535

 

6. 리눅스 커널 설정

- 보통은 오라클 설정과 비슷하게 한다.

솔직히 커널 튜닝까지는 자사 SE쪽에서 기존 프로세스대로 설치하고

넘겨줘서 보지 않았다 추후 공부할 예정이다.

-- 참조 사이트 : https://neo-orcl.tistory.com/tag/parameter

 

vi /etc/sysctl.conf

# Controls IP packet forwarding
net.ipv4.ip_forward = 0
# Controls source route verification
net.ipv4.conf.default.rp_filter = 1
# Do not accept source routing
net.ipv4.conf.default.accept_source_route = 0
# Controls the System Request debugging functionality of the kernel
kernel.sysrq = 0
# Controls whether core dumps will append the PID to the core filename.
# Useful for debugging multi-threaded applications.
kernel.core_uses_pid = 1
# Controls the use of TCP syncookies
net.ipv4.tcp_syncookies = 1
# Disable netfilter on bridges.
#net.bridge.bridge-nf-call-ip6tables = 0
#net.bridge.bridge-nf-call-iptables = 0
#net.bridge.bridge-nf-call-arptables = 0
# Controls the default maxmimum size of a mesage queue
kernel.msgmnb = 65536
# Controls the maximum size of a message, in bytes
kernel.msgmax = 65536
# Controls the maximum shared segment size, in bytes
kernel.shmmax = 68719476736
# Controls the maximum number of shared memory segments, in pages
kernel.shmall = 4294967296
# swap setting
vm.swappiness=0
net.ipv4.tcp_fin_timeout=1
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1
net.ipv4.tcp_keepalive_time=10
net.ipv4.tcp_keepalive_probes=2
net.ipv4.tcp_keepalive_intvl=2
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_syn_retries=1
net.ipv4.tcp_max_syn_backlog=8192

 

 

7. malloc 을 리눅스 OS에 기본설정말고 다른 걸로 바꿔라?

- 뮤택스 락부분에서 개선이 있다고 해서 jemalloc, tcmalloc 둘다 깔아서 써봤는데 별차이 없었다. 그냥 안쓰는 걸로..

 

8. CPU affinity 설정

- 누마(NUMA) 가 좋다고 해서 설정해봤는데 성능은 별차이 없었고

아직 개념이랑 왜 쓰는지 잘 모르겠다. 좀 더 확인해봐야 할 거 같다.

 

 

 

반응형
블로그 이미지

dung beetle

취미는 데이터 수집 직업은 MYSQL과 함께 일하는 DBA의 소소한 일상 이야기

,
반응형

20분 내외면 수행이 끝났던 월배치 중 하나가

2시간이 넘게 걸리면 연관배치들이 지연처리되면 서비스에 문제가 발생하였다.

 

문제의 sql는 update 를 하는 구문이었고

 

이를 select로 변경하고 실행계획을 분석하던 중에 문제의 원인에 접근했다.

 

 

1.  슬로우쿼리 확인

 

 

#1) AS_IS

explain
select count(*) from TB_AAA T1
INNER JOIN TB_BBB T2            
ON T1.SEQ_NO = T2.SEQ_NO          
INNER JOIN TB_CCC T3 /* 24GB 파티션 테이블 */
ON T1.SEQ_NO = T3.SEQ_NO
WHERE T1.CHNG_DTTM BETWEEN DATE_FORMAT(CONCAT('202305', '01'),'%Y-%m-%d 00:00:00')                        
AND DATE_FORMAT(LAST_DAY(CONCAT('202305', '01')),'%Y-%m-%d 23:59:59')
;

value)
1	SIMPLE	T2	index	IDX_BBB_01		IDX_BBB_01	11			1314006		Using where; Using index
1	SIMPLE	T1	eq_ref	PRIMARY,IDX_AAA_06	PRIMARY		8	XXX.T2.SEQ_NO	1		Using where
1	SIMPLE	T3	ref	IDX_CCC_07		IDX_CCC_07	9	XXX.T2.SEQ_NO	1		Using index

 

# 인덱스 스캔 방법 중 index 란?
인덱스를 처음부터 끝까지 탐색하여 데이터를 찾는 방식 (Index Full scan)

-> index 라고 인덱스 스캔이 잘 된다고 생각하면 안된다 인덱스 스캔을 하는 방식 중에 성능이 매우 떨어지는 방식이다.

 

update문에서 where 조건절 T1.TB_AAA의 컬럼 CHNG_DTTM은

IDX_AAA_06 이라는 인덱스가 있는데

 

조건값 '2023-05-01 00:00:00 ~ 2023-05-31 23:59:59' 가 인덱스를 사용할 수 있는 범위에 해당함에도

이것을 옵티마이져가 제대로 활용하지 못하는 것을 알게 되었다.

 

 

 

옵티마이져가 정말 멍청했는지 직접 인덱스를 할당해서 확인해본다.

 

# TO_BE)

explain
select count(*) from TB_AAA T1 force index (IDX_AAA_06)
INNER JOIN TB_BBB T2            
ON T1.SEQ_NO = T2.SEQ_NO          
INNER JOIN TB_CCC T3 /* 24GB 파티션 테이블 */
ON T1.SEQ_NO = T3.SEQ_NO
WHERE T1.CHNG_DTTM BETWEEN DATE_FORMAT(CONCAT('202305', '01'),'%Y-%m-%d 00:00:00')                        
AND DATE_FORMAT(LAST_DAY(CONCAT('202305', '01')),'%Y-%m-%d 23:59:59')
;

value)
1	SIMPLE	T1	range	IDX_AAA_06	IDX_AAA_06	6			135160		Using index condition
1	SIMPLE	T2	ref	IDX_BBB_01	IDX_BBB_01	9	XXX.T1.SEQ_NO	1		Using index
1	SIMPLE	T3	ref	IDX_CCC_07	IDX_CCC_07	9	XXX.T1.SEQ_NO	1		Using index

 

실행계획으로 보았을 때는 인덱스가 range 스캔으로 풀리는 것으로 보아 더 나은 방식으로 보인다.

 

# 인덱스 스캔 방법 중 ragne 란?

특정 범위 내에서 인덱스를 사용하여 원하는 데이터를 추출한다.

-> ref나 eq_ref보다는 느리지만 그래도 쓸만한 인덱스 검색방식이다. (range_optimizer_max_mem_size 변수와 연관있음)

 

하지만 옵티마이져는 최종 sql 실행시 가장 빠른 방식을 스스로 검색해서 실행계획을 세우기 때문에

반드시 위 인덱스 스캔이 더 빠르다고 판단할 수 없다.

 

실제로 select 문을 실행해 보아야한다.

 

#1) AS_IS 수행시간  ->  22초

#2) TO_BE 수행시간 -> 16초

 

음...

 

 

실제로 옵티마이져가 제대로 실행계획을 세우지 못한 것을 확인했다.

이번에는 옵티마이져가 영리하지 못했다.

 

 

 

2. 원인분석

 

 

그럼 왜 이런 일이 발생한 것일까?

 

그것은 update를 처리하는 테이블과 join 된 파티션 테이블의 용량이 문제였다

파티션 테이블에 별도의 조건값이 없어 파티션 푸르닝이나

파티션의 인덱스를 제대로 활용하지 못하고

통째로 join을 하다보니

 

버그인지는 모르겠지만 ( mariadb ver 10.4.18)
옵티마이져가 조건절의 값이 인덱스가 있음에도 제대로 활용하지 못하는 현상이 발생했다.

 

그럼 24GB나 되는 파티션 테이블을 조인해서 사용도 안하는데

 

왜 조인했나?

 

 

대부분의 화면에서 조회하는 sql은 보통 동적쿼리다.

 

이것이 DBA 입장에서는 상당히 머리가 아파질 수 있는 부분인데

 

예를 들어 신규 개발 SQL을 검수할 때 (동적쿼리라면)

서비스환경을 적대적으로 가정하고 그것에 대한 경우의 수를 생각해

실행계획이나 추가인덱스 설정등..SQL을 더 꼼꼼하게 확인해야하는 어려움이 있다.

 

이번 발생한 슬로우 쿼리 또한

웹페이지에서 조회시 TB_CCC(파티션 테이블)와 관련된 검색조건은 빼고 검색을 해도

조회가 되도록 되어있을 것이다.

 

 

 

3. 해결방법

 

 

 

가장 좋은 해결방법은 TB_CCC(파티션 테이블)에

파티션 푸르닝을 사용할 수 있게 조건값을 추가하거나

아니면 TB_CCC(파티션 테이블)의 용량 자체를 줄여서
옵티마이져가 멍때리지 않고 제대로 역할을 할 수 있게 환경을 만들어 주는 것

 

 

여기서 궁금한 게 생겨 테스트를 해봄!


Test) 

대용량 테이블(TB_CCC)의 파티션을 삭제하면서
언제쯤 옵티마이져가 정상적으로 조건절의 인덱스 값을 가져다 플랜을 만드는지 확인해 보았다.

월별 파티션을 하나씩 지우면서 플랜을 뜨다보니

TB_CCC의 용량이 24GB에서 22GB 로 줄었을 때!

드디어 옵티마이져가 where 조건절의 인덱스 IDX_AAA_06 가져다 실행계획을 세우는 것을 확인함

(아. 그래서 얼마전까지는 발생안했고 이번에 발생했구나...^^;)

 

explain)
1 SIMPLE T1 range	PRIMARY,IDX_AAA_06 	IDX_AAA_06 6 			134702 	Using where; Using index
1 SIMPLE T2 ref 	IDX_BBB_01 		IDX_BBB_01 9 	XXX.T1.SEQ_NO 	1 	Using index
1 SIMPLE T3 ref		IDX_CCC_07 		IDX_CCC_07 9 	XXX.T1.SEQ_NO 	1 	Using index


TB_CCC(파티션 테이블) 의 조인 컬럼 SEQ_NO 의 인덱스를 메모리에 올려 실행계획을 세울 때

옵티마이져가 판단하는데도 MAX 가 있는 것으로 보임

 

 24GB가 넘어가면서 문제가 생겼는데..
이것이 22GB 줄었을 때는 옵티마이저가 다시 재정신을 차림

 

검증은 끝났고 

화면에서 파티션 푸르닝 기능을 사용할 수 있는지 개발과 협의해 봐야겠고,

TB_CCC(파티션 테이블)의 데이터 용량은 삭제 주기를 정해서 6개월 이내의 데이터는 삭제하는 것으로 사업부서와 협의해봐야겠다.

force index까지는 사용하지 않고 끝났으면 좋겠다.

 

 

4.결론

 

대용량 파티션 테이블 join 사용법

1) 가능하면 파티션 푸르닝이 포함된 컬럼을 where 조건절에 넣는다.

2) 그것이 안되면 파티션 삭제주기를 정해서 주기적으로 파티션 테이블 용량을 관리한다.

3) 이것도 안될시에는 파티션 테이블을 사용하는 sql을 주기적으로 모니터링하면서
인덱스 스캔이 불가능해지면 forec index로 인덱스를 강제로 할당한다.

 


#파티션 푸르닝이란?
파티션 프루닝(pruning)은 MySQL 에서 WHEHE 구문에 사용된 조회 조건에 만족한 파티션만 추출하는 기능이다.
최적화 단계에서 필요한 파티션만 골라내고 불필요한 것들은 배제하는 것 입니다.
파티션 프루닝은 SELECT, DELETE, UPDATE 구문에서만 가능합니다.

 

 

끝.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
블로그 이미지

dung beetle

취미는 데이터 수집 직업은 MYSQL과 함께 일하는 DBA의 소소한 일상 이야기

,
반응형

슬로우 쿼리 로그 파일에는 long_query_time 시스템 변수에 설정한 시간 이상의 시간이 소요된 쿼리가 모두 기록된다.
(long_query_time 파라미터는 초단위로 설정하지만 소수점 값으로 설정하면 마이크로 초 단위로 설정 가능함)

 

ex)

만약 2초이상 걸리는 쿼리를 슬로우쿼리로 보고 파일로 쌓는 구조를 만드려면?

 

solution)

my.cnf에서 2군데 추가해주면 된다 

 


vi /etc/my.cnf

 

[mysqld]
slow_query_log_file=/data/mysqldb_logs/slow/mysql-slow-query.log /* 슬로우쿼리가 파일로 들어갈 경로 지정 */
long_query_time=2 /* 몇초 이상의 쿼리를 슬로우 쿼리로 만들지 파라미터 값 지정 */



#슬로우 쿼리 설정여부 확인

mysql> show global variables like 'long_query_time';
+-----------------+----------+
| Variable_name   | Value    |
+-----------------+----------+
| long_query_time | 2.000000 |
+-----------------+----------+
1 row in set (0.00 sec)




슬로우 쿼리 로그는 Mysql이 쿼리를 실행한 후, 실제 소요된 시간을 기준으로 슬로우 쿼리 로그에 기록할지 여부를 판단하기 때문에 반드시 쿼리가 정상적으로 실행이 완료되야 슬로우 쿼리로그에 기록될 수 있다. 

즉 슬로우 쿼리 록 파일에 기록되는 쿼리는 일단 정상적으로 실행이 완료됐고 실행하는데 걸린 시간이 long_query_time에 정의된 시간보다 많이 걸린 쿼리인 것이다.
(ex 장애나서 급하게 kill session_id; 시킨 쿼리는 슬로우 쿼리 로그에 남지 않는다^^;)

log_output 옵션을 이용해서 슬로우 쿼리 로그를 파일로 기록할지 테이블로 기록할지 선택할 수 있다.
log_output 옵션을 TABLE로 설정하면 제너럴 로그나 슬로우 쿼리 로그를 

mysql DB의 테이블(general_log와 slow_log 테이블)에 저장하며, 
FILE로 설정하면 로그의 내용을 디스크의 파일로 저장한다.

log_output 옵션을 TABLE로 설정하더라도 mysql DB의 slow_log 테이블과 

general_log 테이블은 CSV 스토리지 엔진을 사용하기 때문에
결국 CSV 파일로 저장하는 것과 동일하게 작용한다.

 

 


하지만 테이블에 굳이 DB에 슬로우쿼리 로그를 쌓을 이유가 없다

 

일단 테이블에 쌓는다면 로그를 삭제 할 때도 DB부하가 발생하고

삭제도 마음대로 못함!

 

그리고  DB부하 발생시 정상적인 쿼리도

처리가 지연되면서 slow query log에 쌓일 텐데
이럴경우 DB 부하가 x2배가 되는 상황을 볼 것이기 때문

 

괜히 건드리지말고 그냥 default 로 둔다^^

 


#log_output 옵션 확인

mysql> show global variables like 'log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output    | FILE  |
+---------------+-------+
1 row in set (0.00 sec)




#slow query 파일로그  확인 방법

# Time: 2023-04-25T16:49:49.018595+09:00
# User@Host: xxxapp[xxxapp] @  [192.168.141.108]  Id: 9000323
# Query_time: 2.529181  Lock_time: 0.000406 Rows_sent: 22  Rows_examined: 781358
SET timestamp=1682408989;
/* sql_id */   SELECT  *    FROM  (     SELECT xxx_CD




파일에서 보는 것 처럼 

Time, User@Host, Query_time, Lock_time, Rows_sent, Rows_examined, ,slow query  sql 등
총 7가지 정도의 정보를 확인할 수 있다

다른 건 다 건너뛰고 장애시 로그 분석할 때 유용한 것과 튜닝할 때 필요한 것만 확인한다.

 


1. DB부하나 장애 발생했을 때

 

#1) User@Host

 

부하를 발생시킨 어플리케이션 서버이다.
일단 평소보다 호출이 많았는지 서버 로그에서 확인하고
DDos등 공격이 아니라면

xxxapp 계정으로 192.168.141.108 서버 -> DB로 들어온 query 처리가 지연되어서
슬로우쿼리가 되었고 실행계획을 확인해서 튜닝할지를 결정한다.

 


#2) Time

 

여기서 가장 중요한 것은 Time은 query가 끝난 시각이다.
(slow query는 쿼리실행이 종료되어야만 로그에 남는다.
중간에 kill 하거나 수행실패한 경우는 general log를 on 하지 않는 이상 남지 않는다)

 

이 말은 부하 시점은  2023-04-25T16:49:49 에서 Query_time: 2.529181(초) 을 뺀 시각
처음 쿼리 수행일 시작한 시각이 되고 
부하를 일으킨 app 서버에서 DB로 쿼리수행요청을 한 시각이 된다.

그렇다면 위 query가 시작한 시각은  2023-04-25 / 16:49:46초 이다.

 


2. 슬로우쿼리 튜닝 때

 

#3) Query_time

 

#1) 로그 분석방법
장애 때는 context switching이 발생하여 쿼리 수행이 지연되기 때문에
정상적인 쿼리도 전부 slow query로 전부 슬로우 쿼리로 찍히는 경우가 많다.

이럴 경우 정상적일 때 slow query 로그와 비교해서
장애 때만 특별히 길게 수행된 쿼리를 찾아낸다.

 

 

#2) 실제 확인할 값
Query_time: 2.529181 말고는 나머지는 딱히 도움될 만한 게 없다.
explain을 확인후 실제 쿼리를 돌려보고 정말
Query_time 만큼의 시간이 걸린다면 
튜닝을 하면 된다.

 

 

 

 

#참조 : real mysql 8.0

반응형
블로그 이미지

dung beetle

취미는 데이터 수집 직업은 MYSQL과 함께 일하는 DBA의 소소한 일상 이야기

,
반응형

고도화 프로젝트 후 SI는 철수하고..

 

한달쯤 지났을까?

 

제일 보고 싶지않은 에러가 떴다.

mysqld got signal 6

DB 재시작이슈가 발생했다

 

에러로그를 확인해보니

 

2023-01-04 16:14:27 0x7f76a70d3700  InnoDB: Assertion failure in thread 140147585529600 in file trx0trx.ic line 213
InnoDB: Failing assertion: !trx->has_search_latch
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
07:14:27 UTC - mysqld got signal 6 ;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
Attempting to collect some information that could help diagnose the problem.
As this is a crash and something is definitely wrong, the information
collection process might fail.

key_buffer_size=33554432
read_buffer_size=2097152
max_used_connections=154
max_threads=1000
thread_count=128
connection_count=128
It is possible that mysqld could use up to 
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 10286111 K  bytes of memory
Hope that's ok; if not, decrease some variables in the equation.

Thread pointer: 0x7f73bc69cf00
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
stack_bottom = 7f76a70d2e28 thread_stack 0x30000
/data/bin/mysqld(my_print_stacktrace+0x35)[0xf45e05]
/data/bin/mysqld(handle_fatal_signal+0x4a4)[0x7cd464]
/lib64/libpthread.so.0[0x316c40f7e0]
/lib64/libc.so.6(gsignal+0x35)[0x316c0324f5]
/lib64/libc.so.6(abort+0x175)[0x316c033cd5]
/data/bin/mysqld(_Z18ut_print_timestampP8_IO_FILE+0x0)[0x7bc9ce]
/data/bin/mysqld[0x1045499]
/data/bin/mysqld(_Z18close_thread_tableP3THDPP5TABLE+0x288)[0xcc1468]
/data/bin/mysqld(_Z19close_thread_tablesP3THD+0x31b)[0xcc1e6b]
/data/bin/mysqld(_ZN18Prepared_statement7prepareEPKcm+0x728)[0xd3e2f8]
/data/bin/mysqld(_Z19mysqld_stmt_prepareP3THDPKcj+0x106)[0xd3f226]
/data/bin/mysqld(_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command+0xb1d)[0xd18dcd]
/data/bin/mysqld(_Z10do_commandP3THD+0x194)[0xd1a324]
/data/bin/mysqld(handle_connection+0x29c)[0xdea0fc]
/data/bin/mysqld(pfs_spawn_thread+0x174)[0xfbdbf4]
/lib64/libpthread.so.0[0x316c407aa1]
/lib64/libc.so.6(clone+0x6d)[0x316c0e8c4d]

Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (7f73bdc4fb10):  SELECT DISTINCT        CC.*        ,
Connection ID (thread ID): 2486689
Status: NOT_KILLED

The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains
information that should help you find out what is causing the crash.
2023-01-04T07:14:27.827525Z mysqld_safe Number of processes running now: 0
2023-01-04T07:14:27.830702Z mysqld_safe mysqld restarted
2023-01-04T16:14:28.009437+09:00 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
2023-01-04T16:14:28.009545+09:00 0 [Note] --secure-file-priv is set to NULL. Operations related to importing and exporting data are disabled
2023-01-04T16:14:28.009569+09:00 0 [Note] /data/bin/mysqld (mysqld 5.7.19-log) starting as process 137699 ...
2023-01-04T16:14:28.014665+09:00 0 [Note] InnoDB: PUNCH HOLE support available
2023-01-04T16:14:28.014690+09:00 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2023-01-04T16:14:28.014694+09:00 0 [Note] InnoDB: Uses event mutexes
2023-01-04T16:14:28.014699+09:00 0 [Note] InnoDB: GCC builtin __sync_synchronize() is used for memory barrier
2023-01-04T16:14:28.014702+09:00 0 [Note] InnoDB: Compressed tables use zlib 1.2.3
2023-01-04T16:14:28.014706+09:00 0 [Note] InnoDB: Using Linux native AIO
2023-01-04T16:14:28.015218+09:00 0 [Note] InnoDB: Number of pools: 1
2023-01-04T16:14:28.015308+09:00 0 [Note] InnoDB: Using CPU crc32 instructions
2023-01-04T16:14:28.017142+09:00 0 [Note] InnoDB: Initializing buffer pool, total size = 96G, instances = 8, chunk size = 128M
2023-01-04T16:14:32.330216+09:00 0 [Note] InnoDB: Completed initialization of buffer pool
2023-01-04T16:14:32.942852+09:00 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
2023-01-04T16:14:32.955591+09:00 0 [Note] InnoDB: Highest supported file format is Barracuda.
2023-01-04T16:14:33.368638+09:00 0 [Note] InnoDB: Log scan progressed past the checkpoint lsn 861023653783
2023-01-04T16:14:33.491857+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861028896256
2023-01-04T16:14:33.560747+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861034139136
2023-01-04T16:14:33.634813+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861039382016
2023-01-04T16:14:33.732145+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861044624896
2023-01-04T16:14:33.809235+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861049867776
2023-01-04T16:14:33.882321+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861055110656
2023-01-04T16:14:33.951426+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861060353536
2023-01-04T16:14:34.018926+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861065596416
2023-01-04T16:14:34.087345+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861070839296
2023-01-04T16:14:34.157479+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861076082176
2023-01-04T16:14:34.222135+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861081325056
2023-01-04T16:14:34.289957+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861086567936
2023-01-04T16:14:34.383546+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861091810816
2023-01-04T16:14:34.428047+09:00 0 [Note] InnoDB: Doing recovery: scanned up to log sequence number 861095311315
2023-01-04T16:14:34.428365+09:00 0 [Note] InnoDB: Database was not shutdown normally!
2023-01-04T16:14:34.428373+09:00 0 [Note] InnoDB: Starting crash recovery.
2023-01-04T16:14:34.664412+09:00 0 [Note] InnoDB: Starting an apply batch of log records to the database...
InnoDB: Progress in percent: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 
2023-01-04T16:14:39.164388+09:00 0 [Note] InnoDB: Apply batch completed
2023-01-04T16:14:39.164433+09:00 0 [Note] InnoDB: Last MySQL binlog file position 0 1770351, file name mysql-bin.002910
2023-01-04T16:14:39.376296+09:00 0 [Note] InnoDB: Removed temporary tablespace data file: "ibtmp1"
2023-01-04T16:14:39.376322+09:00 0 [Note] InnoDB: Creating shared tablespace for temporary tables
2023-01-04T16:14:39.376352+09:00 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
2023-01-04T16:14:39.380934+09:00 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
2023-01-04T16:14:39.381506+09:00 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
2023-01-04T16:14:39.381516+09:00 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
2023-01-04T16:14:39.382232+09:00 0 [Note] InnoDB: Waiting for purge to start
2023-01-04T16:14:39.432361+09:00 0 [Note] InnoDB: 5.7.19 started; log sequence number 861095311315
2023-01-04T16:14:39.432402+09:00 0 [Note] InnoDB: page_cleaner: 1000ms intended loop took 6490ms. The settings might not be optimal. (flushed=0 and evicted=0, during the time.)
2023-01-04T16:14:39.433144+09:00 0 [Note] InnoDB: Loading buffer pool(s) from /data/mysqldb_data/ib_buffer_pool
2023-01-04T16:14:39.441399+09:00 0 [ERROR] Function 'federated' already exists
2023-01-04T16:14:39.441413+09:00 0 [Warning] Couldn't load plugin named 'federated' with soname 'ha_federated.so'.
2023-01-04T16:14:39.441750+09:00 0 [Note] Recovering after a crash using /data/mysqldb_logs/binary/mysql-bin
2023-01-04T16:14:39.447539+09:00 0 [Note] Starting crash recovery...
2023-01-04T16:14:39.447569+09:00 0 [Note] Crash recovery finished.
2023-01-04T16:14:39.453180+09:00 0 [Warning] Failed to set up SSL because of the following SSL library error: SSL context is not usable without certificate and private key
2023-01-04T16:14:39.453197+09:00 0 [Note] Server hostname (bind-address): '*'; port: 3306
2023-01-04T16:14:39.453246+09:00 0 [Note] IPv6 is available.
2023-01-04T16:14:39.453257+09:00 0 [Note]   - '::' resolves to '::';
2023-01-04T16:14:39.453273+09:00 0 [Note] Server socket created on IP: '::'.
2023-01-04T16:14:39.475051+09:00 0 [Note] Event Scheduler: Loaded 0 events
2023-01-04T16:14:39.475194+09:00 0 [Note] /data/bin/mysqld: ready for connections.
Version: '5.7.19-log'  socket: '/tmp/mysql.sock'  port: 3306  MySQL Community Server (GPL)
2023-01-04T16:14:39.475230+09:00 0 [Note] Executing 'SELECT * FROM INFORMATION_SCHEMA.TABLES;' to get a list of tables using the deprecated partition engine. You may use the startup option '--disable-partition-engine-check' to skip this check. 
2023-01-04T16:14:39.475234+09:00 0 [Note] Beginning of list of non-natively partitioned tables
2023-01-04T16:14:39.523762+09:00 0 [Note] End of list of non-natively partitioned tables
2023-01-04T16:15:27.809630+09:00 148 [Note] Start binlog_dump to master_thread_id(148) slave_server(101), pos(mysql-bin.002910, 1792665)

 

1. mysql.error 로그 분석

 

이 로그는 InnoDB 스토리지 엔진의 어설션 오류로 인해 2023년 1월 4일 07:14:27 UTC에 MySQL 서버 프로세스가 중단된 것을 보여줍니다
로그는 파일 trx0trx.ic의 line 213의 스레드 140147585529600에서 어설션 오류가 발생했으며
어설션 오류는 !trx-> has_search_latch였습니다. 
트랜잭션에 검색 래치가 있기 때문에 어설션에 실패했습니다. 

(Assertion : 쿼리의 결과를 만족하는지 체크합니다)

오류 메시지는 자세한 버그 보고서를 http://bugs.mysql.com 에 제출하는 것을 권장합니다.

로그에는 mysqld 프로세스가 버그, 이진/라이브러리 손상, 잘못된 구성 또는 하드웨어 오작동을 나타낼 수 있는 

신호 6을 수신했음도 표시됩니다. 
로그는 문제를 진단하기 위해 더 많은 정보를 수집할 것을 제안합니다.

역추적을 통해 close_thread_table, Prepared_stmt_prepare, mysqld_stmt_prepare, 
dispatch_command, do_command 및 handle_connection 함수에서 오류가 발생했음을 알 수 있습니다.

충돌 당시 실행 중인 쿼리는 SELECT DISTINCT CC.*였습니다. 
프로세스가 중지되지 않았으며 mysqld가 다시 시작되었습니다. 

 

 

2.  재시작시 호출한 Query 로그 분석 (DB, was)

 

일단 DB에 select 관련 error 로그는 깨져서 확인이 불가능하고 
Was 쪽 로그를 확인요청해서 받아보니

 

SELECT DISTINCT         
	   CC.*         
...
	   , IF(qYn = 'Y', gdoc, IF(oData = '11', '무>제한', IF(oData > 0, CONCAT(oData, oUnt), gdoc))) AS oData   

...

 

무>제한 ??

이거는 무엇인가;

 

 

개발파트에서 확인 실제 xml을 보니 실제 이런 구문은 없었고.. 뭔가 부등호가 지맘대로 거기 들어가 붙어있었다

(부등호의 순간이동;;)

 

원인을 찾아보니
mybatis 를 사용 중인데 수식에 부등호를 쓰면서 (<![CDATA[  ]]>) 처리하지 않고 그대로 사용한 것으로 확인했다.

(<![CDATA[  ]]>) 쓰지 않을거면 

&lt;
부등호(<)
 
&gt;
부등호(>)

로 치환해서 써야하는데 그렇게 사용하지 않아서 이상한 쿼리를 끝내지 못하고 
결국 프로세스를 재시작하면서 DB가 재시작된 것이다.

근데 저대로면 빌드가 안 되었을텐데... 어떻게 빌드된 파일로 올라갔을까? 

(실제로 개발에서 테스트 했을 때도 빌드에러남ㅋㅋ)

 





3. 해결

문제가 된 query의 부등호 사용 부분을 아래처럼

<![CDATA[

쿼리 내용

]]>

 

CDATA로 감싸서 처리하고 현재까지 DB 재시작이슈는 발생하지 않았다.

 

 

그리고 이번에 발생한 CDATA 이슈에 관해 간략하게 정리한다.

 


4. CDATA  사용관련 내용정리


MyBatis 사용 시 쿼리문에 비교 연산자와 같이 부등호 처리가 필요할 때가 있다.
하지만 비교 연산자를 사용했을 경우 error를 발생시키는데 그 이유는 비교 연산자인지 괄호인지 구분하지 못하기 때문이다.

비교 연산자를 사용했을 때 MyBatis는 괄호인지 비교 연산자인지 구분하지 못한다.
이런 경우에 CDATA를 사용하면 CDATA 안에 들어가는 문장을 문자열로 인식해 구분할 수 있도록 도와준다.

 

 


1) CDATA란?

 

- (Unparsed) Character Data. 다시말하면 파싱하지 않는 문자 데이터 라는 뜻이다.
파싱하는 문자데이터는 PCDATA 라고 부름

 

 

 

2) CDATA를 사용하는 이유?

 

CDATA 안에 쿼리를 사용하면 쿼리 내용의 괄호나 특수문자를 XML parser로 인식하지 않고 "문자열"로 인식한다

쿼리를 작성할 때, '<', '>', '&'를 사용해야하는 경우가 생기는데 xml에서 그냥 사용할 경우 태그로 인식하는 경우가 종종 있다. 
이럴 경우 에러를 뱉어내기 때문에 '태그가 아니라 실제 쿼리에 필요한 코드'라고 알려줘야 한다. 그때 사용하는 것이 <![CDATA[...]]> 이다.

한 마디로 <>(부등호),&(앤드),||(오아) 등을 닫는 부등호가 아니라 문자열로 처리하라는 뜻입니다.
어렵게 말하자면 "XML parser"를 하지 말아라

 

 


3) CDATA 사용방법

 

<![CDATA[

쿼리 내용

]]>

 



4) CDATA를 안 쓸 때 부등호 처리

 

&nbsp;
” ” : 공백(스페이스 한 칸)을 의미
 
&lt;
부등호(<)
 
&gt;
부등호(>)
 
&amp;
앰퍼샌드(&) 기호
 
&quot;
쌍따옴표(“)
 
&#035;
sharp(#)
 
&#039;
따옴표(‘)

(&lt; 는 Less Than (<, 보다 작은) , &gt; 는 Greater Than (>, 보다 큰) 의 약자라고 한다.)

 


끝.

반응형
블로그 이미지

dung beetle

취미는 데이터 수집 직업은 MYSQL과 함께 일하는 DBA의 소소한 일상 이야기

,
반응형

원래대로라면 15초 내에 종료되었어야 할 프로시저가 1시간이 지나도 끝나지 않고

관련 테이블의 LOCK 까지 발생하여
확인해보니 name_const()로 변환되는 부분에서 문제가 있는 것을 확인하였다.

 

해결과정까지 가는 건 많은 시간이 소요되었지만 결국 답을 찾았고 관련 기록을 정리한다.

 

DB ver: mysql 5.7.1x


1. 장애프로시저 확인

 

CREATE PROCEDURE `xxxx`.`SP_xxxx_LIST`(
in VAR_DATE VARCHAR(20)
)
BEGIN
	DECLARE varMonth varchar(6);
   
	set varMonth = DATE_FORMAT(date_sub(now(),interval +1 MONTH),'%Y%m');
	

	update TB_TEMP_TABLE
	SET RCP_DT = CDP_DT 
	where TG_YYMM = varMonth
	and CAST_CD in ('xxx','xxx')
	and LENGTH(RCP_DT) !=8;

........




2.  원인분석

 

mysql > show full processlist;

/* 프로시저 중간에 이 부분에서 지연이 발생함을 확인함 */

| 591165 | xxxxadm      | 192.168.141.202:49131 | xxxx | Query   |  3638 | Updating                 | update TB_TEMP_TABLE
	SET RCP_DT = CDP_DT 
	where TG_YYMM = NAME_CONST('varMonth',_utf8mb4'202212' COLLATE 'utf8mb4_unicode_ci') 
	and CAST_CD in ('xxx','xxx')
	and LENGTH(RCP_DT) !=8 |    0.000 |



#1. 실행계획 확인

explain
select * from TB_TEMP_TABLE
	where TG_YYMM = NAME_CONST('varMonth',_utf8mb4'202212' COLLATE 'utf8mb4_unicode_ci') 
	and CAST_CD in ('xxx','xxx')
	and LENGTH(RCP_DT) !=8;


#result)
1	SIMPLE	TB_TEMP_TABLE	range	IDX_TEMP_TABLE_06	IDX_TEMP_TABLE_06	18		99890358	Using where

 

IDX_TEMP_TABLE_06은 CAST_CD의 인덱스이다. (TG_YYMM의 인덱스는 IDX_TEMP_TABLE_04)

TB_TEMP_TABLE 테이블은 대용량 파티션 테이블로 약 80GB 정도의 용량을 갖고 있다.
TG_YYMM = '202212' 값이 
내부 함수인 NAME_CONST('varMonth',_utf8mb4'202212' COLLATE 'utf8mb4_unicode_ci')에 
의해 자동으로 묶였는데 이 부분에서 인덱스 사용을 못하고 있다.




#2. 인덱스가 깨졌는지 확인

 

explain
select * from TB_TEMP_TABLE 
where TG_YYMM = '202212' 
and CAST_CD in ('xxx','xxx')
and LENGTH(RCP_DT) !=8;


#result)
1	SIMPLE	TB_TEMP_TABLE	ref	IDX_TEMP_TABLE_04,IDX_TEMP_TABLE_06	IDX_TEMP_TABLE_04	21	const	4752697	Using where



직접 값을 입력했을시 정상적으로 TG_YYMM의 ref 인덱스를 사용하는 것을 확인함, 인덱스는 정상이다.


#3. 실행엔진이 간혹 잘못된 PLAN을 세울수도 있기때문에 인덱스를 강제로 할당테스트

 

explain
select * from TB_TEMP_TABLE force index (IDX_TEMP_TABLE_04)
where TG_YYMM = NAME_CONST('varMonth',_utf8mb4'202212' COLLATE 'utf8mb4_unicode_ci') 
and CAST_CD in ('xxx','xxx')
and LENGTH(RCP_DT) !=8;

#result)
1	SIMPLE	TB_TEMP_TABLE	ALL					198699556	Using where



실행엔진이 문제인가 싶어 force 인덱스로 강제로 주었는데 아에 full scan해서 쿼리가 끝나지 않음

실행엔진이 멍청한 것도 아니다!

 


#4. 확인결과


인덱스는 문제없고 procedure내에서 선언한 varchar 타입인 '202212' 값이 
NAME_CONST() 로 내부함수로 자동변환해서 읽히는데 
이 부분에서 왜 인덱스가 안 타는지 좀 더 확인필요!


 


3. 해결과정

 


일단 name_const() 함수에 대해 알아본다.

#1) name_const 함수란?

NAME_CONST( name , value )
지정된 값을 반환합니다. 결과 집합의 열을 생성 할 때 NAME_CONST() 을 사용하면 지정된 이름이 컬럼에 지정됩니다.
결과 집합 열을 생성하는데 사용하면 NAME_CONST()열이 지정된 이름을 갖게 됩니다. 
인수는 상수여야 합니다.

 

#ex)
mysql> SELECT NAME_CONST('myname', 14);
+--------+
| myname |
+--------+
|     14 |
+--------+
1 row in set (0.00 sec)

같은 의미로 쿼리 안에서 AS 로 컬럼의 닉네임을 거는 것과 동일하다.
mysql> SELECT 14 AS myname;
+--------+
| myname |
+--------+
|     14 |
+--------+
1 row in set (0.00 sec)

 


이 함수는 저장 프로시저를 복제할 때 내부적으로 사용됩니다. 
SQL 문에서 명시적으로 사용하는 것은 거의 의미가 없으며 그렇게 사용해서는 안됩니다.

ex)
SELECT NAME_CONST('myname', 14) 
--> name_const() 함수는 mysql 내부에서 사용하는 것으로 user가 굳이 사용할 필요없다는 것


#name_const() 에서 name은 알겠는데 value는 왜 아래처럼 들어가는 것인가?

_utf8mb4'202212' COLLATE 'utf8mb4_unicode_ci'

#이것도 공식 reference에서 확인가능
https://dev.mysql.com/doc/refman/8.0/en/string-literals.html

#9.1.1 문자열 리터럴

A character string literal may have an optional character set introducer and COLLATE clause, 
to designate it as a string that uses a particular character set and collation:

문자열 리터럴 COLLATE에는 특정 문자 집합과 데이터 정렬을 사용하는 문자열로 지정하기 위해 선택적인 문자 집합 소개자와 절이 있을 수 있습니다.

[_charset_name]'string' [COLLATE collation_name]


ex)
SELECT _latin1'string';
SELECT _binary'string';
SELECT _utf8mb4'string' COLLATE utf8mb4_danish_ci;

-> mysql에서 사용하는 default form 이 _utf8mb4'some text' COLLATE 인 것을 확인함


#2) DBA 관련 카페 문의
https://cafe.naver.com/prodba
-> name_const() 함수로 인해 성능저하가 있었는지 경험많은 DBA분에게 문의하여

여기서 character set 관련 문제로 이슈를 좁힐 수 있었다.


#3) 구글링

비슷한 상황의 질의를 찾았고 해결가능한 힌트를 찾게됨


#MySQL Character Set & Select Query Performance in stored procedure
https://stackoverflow.com/questions/71771201/mysql-character-set-select-query-performance-in-stored-procedure

 

#question)
Recently I noticed few queries are taking very long time in execution, 
checked further and found that MySQL Optimizer is trying to use COLLATE in Where clause 
and that's causing performance issue, if I run below query without COLLATE then getting quick response from database:

최근 몇 가지 쿼리가 실행에 매우 오랜 시간이 걸리는 것을 확인하고 추가로 확인한 결과 
MySQL Optimizer가 Where절에서 COLLATE를 사용하려고 시도하고 있으며 
COLLATE 없이 쿼리 아래에서 실행하면 데이터베이스에서 빠른 응답을 받으면 성능 문제가 

발생한다는 것을 발견했습니다.

SELECT notification_id FROM notification  
WHERE ref_table = 2 
AND ref_id =  NAME_CONST('v_wall_detail_id',_utf8mb4'c37e32fc-b3b5-11ec-befc-02447a44a47c' COLLATE 'utf8mb4_unicode_ci')

 

 

..

Any suggestion, what improvements are needed to make my queries faster?
쿼리 속도를 높이려면 어떤 개선이 필요합니까?

 

#answer)
The table's character set is utf8, so I guess its collation is one of utf8_general_ci or utf8_unicode_ci. 
테이블의 문자 집합이 utf8이므로 데이터 정렬이 utf8_general_ci 또는 utf8_unicode_ci 중 하나인 것 같습니다.

You can check this way:
다음과 같이 확인할 수 있습니다.

 

SELECT collation_name from INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = '...your schema...' AND table_name = 'notification'
AND column_name = 'ref_id';


You are forcing it to compare to a string with a utf8mb4 charset and collation

An index is a sorted data structure, and the sort order depends on the collation of the column. 
Using that index means taking advantage of the sort order to look up values rapidly, without examining every row.

When you compared the column to a string with a different collation, MySQL cannot infer that the sort order or string equivalence of your UUID constant is compatible. 
So it must do string comparison the hard way, row by row.

This is not a bug, this is the intended way for collations to work. 
To take advantage of the index, you must compare to a string with a compatible collation. 

utf8mb4 문자 세트 및 데이터 정렬이 있는 문자열과 비교하도록 강제하고 있습니다. 
인덱스는 정렬된 데이터 구조이며 정렬 순서는 열의 데이터 정렬에 따라 다릅니다. 
해당 인덱스를 사용한다는 것은 정렬 순서를 활용하여 모든 행을 검사하지 않고 빠르게 값을 조회한다는 의미입니다.

열을 데이터 정렬이 다른 문자열과 비교할 때 MySQL은 정렬 순서 또는 UUID 상수의 문자열 등가가 호환 가능하다고 추론할 수 없습니다. 
따라서 문자열 비교를 row 단위의 어려운 방식으로 수행해야 합니다.

이것은 버그가 아니며 데이터 정렬이 작동하도록 의도된 방식입니다. 
인덱스를 활용하려면 호환되는 데이터 정렬이 있는 문자열과 비교해야 합니다.

 

 


# 1) mysql 의 default character set , cllation 확인 (my.cnf 설정)

 

mysql> show global variables like '%coll%';
+----------------------+--------------------+
| Variable_name        | Value              |
+----------------------+--------------------+
| collation_connection | utf8mb4_unicode_ci |
| collation_database   | utf8mb4_unicode_ci |
| collation_server     | utf8mb4_unicode_ci |
+----------------------+--------------------+
3 rows in set (0.00 sec)


mysql> show global variables like '%char%';
+--------------------------+----------------------------------------------------------+
| Variable_name            | Value                                                    |
+--------------------------+----------------------------------------------------------+
| character_set_client     | utf8mb4                                                  |
| character_set_connection | utf8mb4                                                  |
| character_set_database   | utf8mb4                                                  |
| character_set_filesystem | binary                                                   |
| character_set_results    | utf8mb4                                                  |
| character_set_server     | utf8mb4                                                  |
| character_set_system     | utf8                                                     ||
+--------------------------+----------------------------------------------------------+
8 rows in set (0.00 sec)

 

 

#2) 컬럼 타입 확인

 

SELECT
CHARACTER_SET_NAME
,COLLATION_NAME 
FROM INFORMATION_SCHEMA.`COLUMNS`  
WHERE TABLE_NAME = 'TB_TEMP_TABLE'
and COLUMN_NAME = 'TG_YYMM';


----------------------------
utf8  |   utf8_general_ci  |
----------------------------

 

 

빙고!

 



4. 해결

 



원인은 TG_YYMM 컬럼은 character set  = utf8이고

mysql 의 my.cnf / default character set = utf8mb4 이 차이가 있어서 발생하였다.

프로시저 내에서 선언한 varMonth varchar(6)은 당연히 mysql default 케릭터셋인 utf8mb4 를 쓰고 있다.

where 절에서

utf8 = utf8mb4 를 비교하니 

mysql에서 

야! varMonth  변수 이거 utf8 아니고 utf8mb4 이야 ."라고 

name_const() 함수를 통해 알려주고 있었고 

 

"이러면 인덱스 못쓴다.!" 라고 

show processlist를 통해 한번 더 알려주고 있었는데

의미를 제대로 알지 못함..^^;




#수정방법은 2가지고 성능은 1번이 조금 더 좋다.

(내부 함수라도 함수를 한번 덜써서 그런것으로 보임)

1) varMonth 선언할 때 TG_YYMM 컬럼과 동일한 character set 으로 변경

 

/* DECLARE varMonth varchar(6) 를 아래처럼 utf8로 명시적으로 선언*/
DECLARE varMonth varchar(6) CHARACTER SET utf8 COLLATE utf8_general_ci; 


#log)

mysql> show full processlist;

update TB_TEMP_TABLE
SET RCP_DT = CDP_DT 
where TG_YYMM =  NAME_CONST('varMonth',_utf8'202212' COLLATE 'utf8_general_ci')
and CAST_CD in ('xxx','xxx')
and LENGTH(RCP_DT) !=8;

 

 

#실행계획


-> NAME_CONST()를 쓰지만 동일한 utf8이기 때문에 ref 인덱스 스캔을 한다.



2) query 문 안에서 수정

 

update TB_TEMP_TABLE
SET RCP_DT = CDP_DT 
where TG_YYMM = CONVERT(varMonth USING utf8)
and CAST_CD in ('xxx','xxx')
and LENGTH(RCP_DT) !=8;


#log)

mysql> show full processlist;

update TB_TEMP_TABLE
SET RCP_DT = CDP_DT 
where TG_YYMM = CONVERT( NAME_CONST('varMonth',_utf8mb4'202212' COLLATE 'utf8mb4_unicode_ci') USING utf8)
and CAST_CD in ('xxx','xxx')
and LENGTH(RCP_DT) !=8

 

 

#실행계획


-> NAME_CONST( _utf8mb4 를 쓰지만 다시 convert 함수로 utf8로 변경해서 결국 ref 인덱스 스캔이 된다.

 


끝.

반응형
블로그 이미지

dung beetle

취미는 데이터 수집 직업은 MYSQL과 함께 일하는 DBA의 소소한 일상 이야기

,
반응형

mysqldump는 mysql, mariadb 에서 데이터 백업시 주로 사용하는 백업방법 중 하나이다.

개발 DB에서 사용할 때는 문제가 없지만

서비스 DB에서 이걸 사용한다면 한가지 주의할 점이 있다.

모르고 그냥 사용하게 된다면 TABLE LOCK 때문에 서비스 장애를 일으킬 수 있다.

mysqldump는 여러 옵션이 있는데 그것을 모르고

default 옵션만 놓고 사용한다면 문제가 발생한다.

 

 

1. default 옵션사용시

 


ex)
mysqldump -uroot -p비번 xxxxDB TB_TEST_HIST > TB_TEST_HIST_20230110.sql

 

MariaDB [(none)]> show processlist;
+----------+-------------+----------------------+-------+---------+------+---------------------------------+------------------------------------------------------------------------------------------------------+----------+
| Id       | User        | Host              	| db    | Command | Time | State                           | Info                                                                                                 | Progress |
+----------+-------------+----------------------+-------+---------+------+---------------------------------+------------------------------------------------------------------------------------------------------+----------+
|        4 | system user |                   	| NULL  | Daemon  | NULL | InnoDB purge worker             | NULL                                                                                                 |    0.000 |
|        2 | system user |                   	| NULL  | Daemon  | NULL | InnoDB purge worker             | NULL                                                                                                 |    0.000 |
|        3 | system user |                   	| NULL  | Daemon  | NULL | InnoDB purge worker             | NULL                                                                                                 |    0.000 |
|        1 | system user |                   	| NULL  | Daemon  | NULL | InnoDB purge coordinator        | NULL                                                                                                 |    0.000 |
|        5 | system user |                   	| NULL  | Daemon  | NULL | InnoDB shutdown handler         | NULL                                                                                                 |    0.000 |
|       32 | xxxbat      | 192.168.141.77:47128 | xxxxDB   | Sleep   |    2 |                                 | NULL                                                                                                 |    0.000 |
| 13659427 | xxxapp      | 192.168.141.75:47836 | xxxxDB   | Sleep   |   42 |                                 | NULL                                                                                                 |    0.000 |
| 13665622 | xxxapp      | 192.168.141.75:48626 | xxxxxxDB | Sleep   |   45 |                                 | NULL                                                                                                 |    0.000 |
| 13665657 | xxxapp      | 192.168.141.75:48632 | xxxxxxDB | Sleep   |   45 |                                 | NULL                                                                                                 |    0.000 |
| 13666109 | xxxapp      | 192.168.141.75:48686 | xxxxxxDB | Sleep   |   45 |                                 | NULL                                                                                                 |    0.000 |
| 13666154 | xxxapp      | 192.168.141.75:48690 | xxxxxxDB | Sleep   |   15 |                                 | NULL                                                                                                 |    0.000 |
| 13666211 | xxxapp      | 192.168.141.75:48700 | xxxxxxDB | Sleep   |   15 |                                 | NULL                                                                                                 |    0.000 |
| 13666735 | xxxapp      | 192.168.141.75:48756 | xxxxDB   | Sleep   |   42 |                                 | NULL                                                                                                 |    0.000 |
| 13667304 | xxxapp      | 192.168.141.75:48820 | xxxxxxDB | Sleep   |   15 |                                 | NULL                                                                                                 |    0.000 |
| 13667820 | xxxapp      | 192.168.141.75:48888 | xxxxxxDB | Sleep   |   15 |                                 | NULL                                                                                                 |    0.000 |
| 13667892 | root        | localhost         	| NULL     | Query   |    0 | Init                            | show processlist                                                                                     |    0.000 |
| 13668007 | root        | localhost         	| xxxxDB   | Query   |  146 | Sending data                    | SELECT /*!40001 SQL_NO_CACHE */ xxxx, xxxx, xxxxx, xxxx, xxxx 	 									 |    0.000 |
| 13668013 | xxxbat      | 192.168.141.77:45250 | xxxxDB   | Query   |  144 | Waiting for table metadata lock | INSERT INTO TB_TEST_HIST (       xxxx       ,xxxx       ,xxxx      ,P 								 |    0.000 |
| 13668017 | xxxbat      | 192.168.141.77:45260 | xxxxDB   | Query   |  128 | Waiting for table metadata lock | INSERT INTO TB_TEST_HIST (       xxxx       ,xxxx       ,xxxx      ,P 								 |    0.000 |
| 13668019 | xxxbat      | 192.168.141.77:45268 | xxxxDB   | Sleep   |  111 |                                 | NULL                                                                                                 |    0.000 |
| 13668026 | xxxbat      | 192.168.141.77:45282 | xxxxDB   | Sleep   |  107 |                                 | NULL                                                                                                 |    0.000 |
| 13668033 | xxxbat      | 192.168.141.77:45298 | xxxxDB   | Query   |  103 | Waiting for table metadata lock | INSERT INTO TB_TEST_HIST (       xxxx       ,xxxx       ,xxxx      ,P								 |    0.000 |
| 13668037 | xxxbat      | 192.168.141.77:45310 | xxxxDB   | Query   |   83 | Waiting for table metadata lock | UPDATE TB_TEST_HIST        SET xxxx = ( SELECT xxxx FROM xxxx WHERE xxxx 							 |    0.000 |
| 13668040 | xxxbat      | 192.168.141.77:45316 | xxxxDB   | Sleep   |   71 |                                 | NULL                                                                                                 |    0.000 |
| 13668044 | xxxbat      | 192.168.141.77:45326 | xxxxDB   | Query   |   69 | Waiting for table metadata lock | INSERT INTO TB_TEST_HIST (       xxxx       ,xxxx       ,xxxx      ,P 								 |    0.000 |
| 13668047 | xxxbat      | 192.168.141.77:45342 | xxxxDB   | Sleep   |   52 |                                 | NULL                                                                                                 |    0.000 |
| 13668055 | xxxbat      | 192.168.141.77:45360 | xxxxDB   | Query   |   45 | Waiting for table metadata lock | INSERT INTO TB_TEST_HIST (       xxxx       ,xxxx       ,xxxx      ,P 								 |    0.000 |
| 13668062 | xxxbat      | 192.168.141.77:45378 | xxxxDB   | Sleep   |   22 |                                 | NULL                                                                                                 |    0.000 |
| 13668069 | xxxbat      | 192.168.141.77:45392 | xxxxDB   | Sleep   |   16 |                                 | NULL                                                                                                 |    0.000 |
| 13668072 | xxxapp      | 192.168.141.75:48930 | xxxxxxDB | Sleep   |   15 |                                 | NULL                                                                                                 |    0.000 |
| 13668077 | xxxbat      | 192.168.141.77:45410 | xxxxDB   | Sleep   |   12 |                                 | NULL                                                                                                 |    0.000 |
| 13668078 | xxxbat      | 192.168.141.77:45412 | xxxxDB   | Sleep   |   11 |                                 | NULL                                                                                                 |    0.000 |
| 13668079 | xxxbat      | 192.168.141.77:45414 | xxxxDB   | Sleep   |   10 |                                 | NULL                                                                                                 |    0.000 |
| 13668080 | xxxbat      | 192.168.141.77:45416 | xxxxDB   | Sleep   |   10 |                                 | NULL                                                                                                 |    0.000 |
| 13668081 | xxxbat      | 192.168.141.77:45418 | xxxxDB   | Sleep   |    9 |                                 | NULL                                                                                                 |    0.000 |
| 13668082 | xxxbat      | 192.168.141.77:45420 | xxxxDB   | Query   |    7 | Waiting for table metadata lock | UPDATE TB_TEST_HIST        SET xxxx = ( SELECT xxxx FROM xxxx WHERE xxxx 							 |    0.000 |
+----------+-------------+-------------------+-------+---------+------+---------------------------------+------------------------------------------------------------------------------------------------------+----------+

 

show processlist로 세션 로그를 보면
mysqldump 를 처리하려고  Sending data  | SELECT /*!40001 SQL_NO_CACHE */ xxxx, xxxx, xxxxx, xxxx, xxxx ~ 를 수행하자
아래로 백업테이블의 DML query가 전부 LOCK 이걸리는 것을 확인할 수 있다. 
(insert 와 update 에서 Waiting for table metadata lock)

이것을 모르고 그냥 둔다면 수초 내로 세션이 늘어나면서 DB 세션이 MAX까지 찰것이고,
결국엔 메모리 부족으로 DB가 죽을 수도 있고, 버틴다면 too many connection 에러를 보고 서비스 접속이 어려워질 수 있다.

서비스 DB에서는 굳이 mysqldump를 안하면 제일 좋긴한데 ...
어쩔 수없이 테이블 백업이 필요한 경우라면?

 

 

2. LOCK 없이 백업방법 

 

1) 트랜잭션 옵션 --single-transaction 적용방법



innoDB 엔진일 때만 사용가능하다.
이 옵션을 지정하면 백업 대상 MYSQL 서버에 백업을 위해 접속한 세션의 트랜잭션 격리 수준을 REPEATABLE READ 로 변경하고, 
백업 시작 직전에 START TRANSACTION 명령을 실행한 뒤 백업을 진행한다. 
이 옵션을 이용하면 백업을 수행할 때 InnoDB 스토리지 엔진과 같이 트랜잭션을 지원하는 스토리지 엔진을 사용하는 테이블에 대해서는 
START TRANSACTION 구문이 실행된 시점의 일관된 데이터를 백업할 수 있다.
(MyISAM 엔진 테이블에서는 사용 x)

이 옵션을 이용해 백업을 수행할 때는 다른 세션에서는 DDL 명령을 실행해서는 안된다. 
큰 테이블을 백업해야 한다면 --single-transaction 과 --quick 옵션을 함께 사용하는 것을 권장

#1-1) 대용량 테이블 백업시 
--quick 성능 관련 옵션추가 
백업 대상 데이터베이스에서 백업할 행 데이터 전체를 한 번에 읽어서 백업한다. 
만일 이 옵션을 사용하지 않는다면 행데이터를 백업 파일에 기록하기 전에 메모리에 먼저 버퍼링하고 백업이 수행되므로 백업 소요 시간이 길어질 수 있다.
그러므로 이 옵션은 백업 대상 테이블 크기가 클 때 유용하게 사용.

 

ex)
mysqldump -uroot -p비번 --single-transaction xxxxDB TB_TEST_HIST > TB_TEST_HIST_20230110.sql

 

MariaDB [(none)]> show processlist;
+----------+-------------+--------------------+-------+---------+------+--------------------------+------------------------------------------------------------------------------------------------------+----------+
| Id       | User        | Host               | db    | Command | Time | State                    | Info                                                                                                 | Progress |
+----------+-------------+--------------------+-------+---------+------+--------------------------+------------------------------------------------------------------------------------------------------+----------+
|        4 | system user |                    | NULL  | Daemon  | NULL | InnoDB purge worker      | NULL                                                                                                 |    0.000 |
|        2 | system user |                    | NULL  | Daemon  | NULL | InnoDB purge worker      | NULL                                                                                                 |    0.000 |
|        3 | system user |                    | NULL  | Daemon  | NULL | InnoDB purge worker      | NULL                                                                                                 |    0.000 |
|        1 | system user |                    | NULL  | Daemon  | NULL | InnoDB purge coordinator | NULL                                                                                                 |    0.000 |
|        5 | system user |                    | NULL  | Daemon  | NULL | InnoDB shutdown handler  | NULL                                                                                                 |    0.000 |
|       32 | xxxbat      | 192.168.141.77:47128  | xxxxDB | Sleep   |    1 |                          | NULL                                                                                                 |    0.000 |
| 13864455 | xxxapp      | 192.168.141.75:53594  | xxxxDB | Sleep   |   48 |                          | NULL                                                                                                 |    0.000 |
| 13864458 | xxxapp      | 192.168.141.75:53596  | xxxxDB | Sleep   |   20 |                          | NULL                                                                                                 |    0.000 |
| 13864520 | xxxapp      | 192.168.141.75:53608  | xxxxxDB | Sleep   |   21 |                          | NULL                                                                                                 |    0.000 |
| 13865142 | xxxapp      | 192.168.141.75:53680  | xxxxxDB | Sleep   |   21 |                          | NULL                                                                                                 |    0.000 |
| 13865509 | xxxapp      | 192.168.141.75:53724  | xxxxxDB | Sleep   |   21 |                          | NULL                                                                                                 |    0.000 |
| 13865563 | xxxapp      | 192.168.141.75:53732  | xxxxxDB | Sleep   |   21 |                          | NULL                                                                                                 |    0.000 |
| 13865618 | xxxapp      | 192.168.141.75:53740  | xxxxxDB | Sleep   |   21 |                          | NULL                                                                                                 |    0.000 |
| 13866108 | xxxapp      | 192.168.141.75:53778  | xxxxxDB | Sleep   |   51 |                          | NULL                                                                                                 |    0.000 |
| 13866170 | xxxapp      | 192.168.141.75:53784  | xxxxxDB | Sleep   |   51 |                          | NULL                                                                                                 |    0.000 |
| 13866229 | root        | localhost          | NULL  | Query   |    0 | Init                     | show processlist                                                                                     |    0.000 |
| 13866233 | xxxapp      | 192.168.141.75:53792  | xxxxxDB | Sleep   |   51 |                          | NULL                                                                                                 |    0.000 |
| 13867099 | xxxbat      | 192.168.141.77:55098  | xxxxDB | Sleep   |  118 |                          | NULL                                                                                                 |    0.000 |
| 13867106 | xxxbat      | 192.168.141.77:55112  | xxxxDB | Sleep   |  114 |                          | NULL                                                                                                 |    0.000 |
| 13867113 | xxxbat      | 192.168.141.77:55132  | xxxxDB | Sleep   |  110 |                          | NULL                                                                                                 |    0.000 |
| 13867121 | xxxbat      | 192.168.141.77:55148  | xxxxDB | Sleep   |  106 |                          | NULL                                                                                                 |    0.000 |
| 13867128 | xxxbat      | 192.168.141.77:55164  | xxxxDB | Sleep   |  102 |                          | NULL                                                                                                 |    0.000 |
| 13867135 | xxxbat      | 192.168.141.77:55178  | xxxxDB | Sleep   |   98 |                          | NULL                                                                                                 |    0.000 |
| 13867142 | xxxbat      | 192.168.141.77:55194  | xxxxDB | Sleep   |   95 |                          | NULL                                                                                                 |    0.000 |
| 13867149 | xxxbat      | 192.168.141.77:55208  | xxxxDB | Sleep   |   91 |                          | NULL                                                                                                 |    0.000 |
| 13867156 | xxxbat      | 192.168.141.77:55222  | xxxxDB | Sleep   |   88 |                          | NULL                                                                                                 |    0.000 |
| 13867163 | xxxbat      | 192.168.141.77:55236  | xxxxDB | Sleep   |   85 |                          | NULL                                                                                                 |    0.000 |
| 13867171 | xxxbat      | 192.168.141.77:55252  | xxxxDB | Sleep   |   81 |                          | NULL                                                                                                 |    0.000 |
| 13867178 | xxxbat      | 192.168.141.77:55268  | xxxxDB | Sleep   |   77 |                          | NULL                                                                                                 |    0.000 |
| 13867185 | xxxbat      | 192.168.141.77:55284  | xxxxDB | Sleep   |   73 |                          | NULL                                                                                                 |    0.000 |
| 13867192 | xxxbat      | 192.168.141.77:55300  | xxxxDB | Sleep   |   70 |                          | NULL                                                                                                 |    0.000 |
| 13867199 | xxxbat      | 192.168.141.77:55316  | xxxxDB | Sleep   |   67 |                          | NULL                                                                                                 |    0.000 |
| 13867206 | xxxbat      | 192.168.141.77:55330  | xxxxDB | Sleep   |   62 |                          | NULL                                                                                                 |    0.000 |
| 13867214 | xxxbat      | 192.168.141.77:55354  | xxxxDB | Sleep   |   59 |                          | NULL                                                                                                 |    0.000 |
| 13867221 | xxxbat      | 192.168.141.77:55368  | xxxxDB | Sleep   |   55 |                          | NULL                                                                                                 |    0.000 |
| 13867228 | xxxbat      | 192.168.141.77:55382  | xxxxDB | Sleep   |   52 |                          | NULL                                                                                                 |    0.000 |
| 13867235 | xxxbat      | 192.168.141.77:55400  | xxxxDB | Sleep   |   49 |                          | NULL                                                                                                 |    0.000 |
| 13867242 | xxxbat      | 192.168.141.77:55414  | xxxxDB | Sleep   |   45 |                          | NULL                                                                                                 |    0.000 |
| 13867249 | xxxbat      | 192.168.141.77:55432  | xxxxDB | Sleep   |   42 |                          | NULL                                                                                                 |    0.000 |
| 13867256 | xxxbat      | 192.168.141.77:55448  | xxxxDB | Sleep   |   39 |                          | NULL                                                                                                 |    0.000 |
| 13867264 | xxxbat      | 192.168.141.77:55466  | xxxxDB | Sleep   |   35 |                          | NULL                                                                                                 |    0.000 |
| 13867271 | xxxbat      | 192.168.141.77:55480  | xxxxDB | Sleep   |   32 |                          | NULL                                                                                                 |    0.000 |
| 13867278 | xxxbat      | 192.168.141.77:55494  | xxxxDB | Sleep   |   29 |                          | NULL                                                                                                 |    0.000 |
| 13867285 | xxxbat      | 192.168.141.77:55510  | xxxxDB | Sleep   |   24 |                          | NULL                                                                                                 |    0.000 |
| 13867292 | xxxbat      | 192.168.141.77:55528  | xxxxDB | Sleep   |   21 |                          | NULL                                                                                                 |    0.000 |
| 13867299 | xxxbat      | 192.168.141.77:55542  | xxxxDB | Sleep   |   17 |                          | NULL                                                                                                 |    0.000 |
| 13867313 | root        | localhost          | xxxxDB | Query   |   11 | Sending data             | SELECT /*!40001 SQL_NO_CACHE */ xxxx, xxxx, xxxxx, xxxx, xxxx 										  |    0.000 |
| 13867315 | xxxbat      | 192.168.141.77:55576  | xxxxDB | Sleep   |    9 |                          | NULL                                                                                                 |    0.000 |
| 13867322 | xxxbat      | 192.168.141.77:55592  | xxxxDB | Sleep   |    6 |                          | NULL                                                                                                 |    0.000 |
| 13867329 | xxxbat      | 192.168.141.77:55608  | xxxxDB | Sleep   |    3 |                          | NULL                                                                                                 |    0.000 |
| 13867336 | xxxbat      | 192.168.141.77:55626  | xxxxDB | Sleep   |    0 |                          | NULL                                                                                                 |    0.000 |
+----------+-------------+--------------------+-------+---------+------+--------------------------+------------------------------------------------------------------------------------------------------+----------+
55 rows in set (0.000 sec)

MariaDB [(none)]>

별도 LOCK이 없는 것을 확인할 수 있다.

 

 

 

2) OUTFILE 사용하는 방법

 

파티션 테이블등 대용량 테이블의 경우 OUTFILE 을 사용한다.
특수문자등이 없다면 가장 빠르게 백업할 수 있는 방법이다.

 

 

ex)
mysql> select * from TB_TEST_HIST

INTO OUTFILE '/data/mariadb_tmp/TB_TEST_HIST_20230110.out';

 

MariaDB [(none)]> show processlist;
+----------+-------------+-------------------+-------+---------+------+--------------------------+------------------------------------------------------------------------------------------------------+----------+
| Id       | User        | Host              | db    | Command | Time | State                    | Info                                                                                                 | Progress |
+----------+-------------+-------------------+-------+---------+------+--------------------------+------------------------------------------------------------------------------------------------------+----------+
|        4 | system user |                   | NULL  | Daemon  | NULL | InnoDB purge worker      | NULL                                                                                                 |    0.000 |
|        2 | system user |                   | NULL  | Daemon  | NULL | InnoDB purge worker      | NULL                                                                                                 |    0.000 |
|        3 | system user |                   | NULL  | Daemon  | NULL | InnoDB purge worker      | NULL                                                                                                 |    0.000 |
|        1 | system user |                   | NULL  | Daemon  | NULL | InnoDB purge coordinator | NULL                                                                                                 |    0.000 |
|        5 | system user |                   | NULL  | Daemon  | NULL | InnoDB shutdown handler  | NULL                                                                                                 |    0.000 |
|       32 | xxxbat      | 192.168.141.77:47128 | xxxxDB   | Sleep   |   18 |                          | NULL                                                                                                 |    0.000 |
| 13659427 | xxxapp      | 192.168.141.75:47836 | xxxxDB   | Sleep   |   59 |                          | NULL                                                                                                 |    0.000 |
| 13666735 | xxxapp      | 192.168.141.75:48756 | xxxxDB   | Sleep   |   59 |                          | NULL                                                                                                 |    0.000 |
| 13667304 | xxxapp      | 192.168.141.75:48820 | xxxxxxDB | Sleep   |    1 |                          | NULL                                                                                                 |    0.000 |
| 13667820 | xxxapp      | 192.168.141.75:48888 | xxxxxxDB | Sleep   |    1 |                          | NULL                                                                                                 |    0.000 |
| 13667892 | root        | localhost         	| NULL     | Query   |    0 | Init                     | show processlist                                                                                     |    0.000 |
| 13668072 | xxxapp      | 192.168.141.75:48930 | xxxxxxDB | Sleep   |    1 |                          | NULL                                                                                                 |    0.000 |
| 13668093 | xxxapp      | 192.168.141.75:48942 | xxxxxxDB | Sleep   |    1 |                          | NULL                                                                                                 |    0.000 |
| 13668154 | xxxapp      | 192.168.141.75:48948 | xxxxxxDB | Sleep   |   31 |                          | NULL                                                                                                 |    0.000 |
| 13668508 | xxxbat      | 192.168.141.77:46352 | xxxxDB   | Sleep   |  119 |                          | NULL                                                                                                 |    0.000 |
| 13668515 | xxxbat      | 192.168.141.77:46370 | xxxxDB   | Sleep   |  111 |                          | NULL                                                                                                 |    0.000 |
| 13668522 | xxxbat      | 192.168.141.77:46386 | xxxxDB   | Sleep   |  108 |                          | NULL                                                                                                 |    0.000 |
| 13668529 | xxxbat      | 192.168.141.77:46400 | xxxxDB   | Sleep   |  102 |                          | NULL                                                                                                 |    0.000 |
| 13668544 | xxxbat      | 192.168.141.77:46430 | xxxxDB   | Sleep   |   86 |                          | NULL                                                                                                 |    0.000 |
| 13668552 | xxxbat      | 192.168.141.77:46446 | xxxxDB   | Sleep   |   82 |                          | NULL                                                                                                 |    0.000 |
| 13668559 | xxxbat      | 192.168.141.77:46464 | xxxxDB   | Sleep   |   79 |                          | NULL                                                                                                 |    0.000 |
| 13668566 | xxxbat      | 192.168.141.77:46478 | xxxxDB   | Sleep   |   75 |                          | NULL                                                                                                 |    0.000 |
| 13668573 | xxxbat      | 192.168.141.77:46496 | xxxxDB   | Sleep   |   71 |                          | NULL                                                                                                 |    0.000 |
| 13668580 | xxxbat      | 192.168.141.77:46510 | xxxxDB   | Sleep   |   68 |                          | NULL                                                                                                 |    0.000 |
| 13668588 | xxxbat      | 192.168.141.77:46530 | xxxxDB   | Sleep   |   64 |                          | NULL                                                                                                 |    0.000 |
| 13668595 | xxxapp      | 192.168.141.75:48996 | xxxxxxDB | Sleep   |   31 |                          | NULL                                                                                                 |    0.000 |
| 13668596 | xxxbat      | 192.168.141.77:46544 | xxxxDB   | Sleep   |   61 |                          | NULL                                                                                                 |    0.000 |
| 13668603 | xxxbat      | 192.168.141.77:46558 | xxxxDB   | Sleep   |   57 |                          | NULL                                                                                                 |    0.000 |
| 13668610 | xxxbat      | 192.168.141.77:46576 | xxxxDB   | Sleep   |   53 |                          | NULL                                                                                                 |    0.000 |
| 13668617 | xxxbat      | 192.168.141.77:46592 | xxxxDB   | Sleep   |   50 |                          | NULL                                                                                                 |    0.000 |
| 13668620 | root        | localhost         	| xxxxDB   | Query   |    3 | Sending data             | select * from TB_TEST_HIST
INTO OUTFILE '/data/mariadb_tmp/TB_TEST_HIST_20230110.out'																																					  |    0.000 |
| 13668625 | xxxbat      | 192.168.141.77:46608 | xxxxDB   | Sleep   |   46 |                          | NULL                                                                                                 |    0.000 |
| 13668632 | xxxbat      | 192.168.141.77:46622 | xxxxDB   | Sleep   |   43 |                          | NULL                                                                                                 |    0.000 |
| 13668640 | xxxbat      | 192.168.141.77:46638 | xxxxDB   | Sleep   |   39 |                          | NULL                                                                                                 |    0.000 |
| 13668647 | xxxbat      | 192.168.141.77:46654 | xxxxDB   | Sleep   |   35 |                          | NULL                                                                                                 |    0.000 |
| 13668653 | xxxapp      | 192.168.141.75:49000 | xxxxxxDB | Sleep   |   31 |                          | NULL                                                                                                 |    0.000 |
| 13668655 | xxxbat      | 192.168.141.77:46668 | xxxxDB   | Sleep   |   29 |                          | NULL                                                                                                 |    0.000 |
| 13668662 | xxxbat      | 192.168.141.77:46682 | xxxxDB   | Sleep   |   22 |                          | NULL                                                                                                 |    0.000 |
| 13668669 | xxxbat      | 192.168.141.77:46700 | xxxxDB   | Sleep   |    5 |                          | NULL                                                                                                 |    0.000 |
| 13668670 | xxxbat      | 192.168.141.77:46702 | xxxxDB   | Sleep   |    4 |                          | NULL                                                                                                 |    0.000 |
| 13668671 | xxxbat      | 192.168.141.77:46704 | xxxxDB   | Sleep   |    3 |                          | NULL                                                                                                 |    0.000 |
| 13668672 | xxxapp      | 192.168.141.75:49010 | xxxxxxDB | Sleep   |    1 |                          | NULL                                                                                                 |    0.000 |
+----------+-------------+-------------------+-------+---------+------+--------------------------+------------------------------------------------------------------------------------------------------+----------+
44 rows in set (0.000 sec)

 

별도 LOCK이 없는 것을 확인할 수 있다.

 

 

 

3. 실제 서비스DB에서는 어떤 것을 사용?

 

 

각 회사마다 sacle-out 방식이 MHA, maxscale, Galera Cluster, Xpand 등등.. 달라서 

 

뭐라고 딱집어서 말하긴 그렇지만

 

많이 사용하는 MHA 구조에서는

 

서비스DB는 Master-Slave 로 이중화되어 있고

보통 전체 daily 백업은 Slave DB에서 xtrabackup을 사용한다.

테이블 단위로 백업이 필요하다면 DB상태와 테이블 사이즈를 봐서 

 

Slave DB에서 mysqldump나 OUTFILE을 적절하게 사용한다.

 

Master DB는 웬만하면 안 건드린다.


끝.

 

 

 

참조: 
https://jmkim.tistory.com/54
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=theswice&logNo=60210698273

반응형
블로그 이미지

dung beetle

취미는 데이터 수집 직업은 MYSQL과 함께 일하는 DBA의 소소한 일상 이야기

,
반응형

mysql 유저 계정에 특정 테이블에 권한 추가를 하려고 기존권한을 복붙 하려는데 

 

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, EXECUTE ON xxxxDB.TB_TEMP_BACKUP TO 'testapp'@'%';

 

ERROR 1144 (42000): Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used


에러가 나서 좀 확인해보니 나머지는 상관없는데 EXECUTE 권한이 전역권한이라 특정테이블에서만 실행할 수는 없다고 한다.


EXECUTE 권한에 대해 알아본다.

EXECUTE : 저장 루틴(저장 프로시저 및 함수)을 실행하는 명령문을 사용할 수 있습니다.
참조 : https://dev.mysql.com/doc/refman/5.7/en/privileges-provided.html

함수나 프로시저를 실행하는 명령어였다. 
(그럼 특정테이블에 EXECUTE 권한 넣는 것은 당연히 안되는 것)

그렇다면 특정함수만 권한넣을 수 있는지와 전역권한이라니까

2가지를  한번 테스트 해본다.

테스트시작)


1.  특정테이블에 권한 추가

mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, EXECUTE ON xxxxDB.TB_TEMP_BACKUP TO 'testapp'@'%';
ERROR 1144 (42000): Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used
/* EXECUTE 때문에 안됨 
xxxxDB.TB_TEMP_BACKUP (DB스키마명.테이블명)
*/



mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON xxxxDB.TB_TEMP_BACKUP to 'testapp'@'%';
Query OK, 0 rows affected (0.04 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)
/* EXECUTE 빼고는 특정테이블에 권한할당이 가능한 것을 확인함 */



2. EXECUTE 권한 테스트



2-1) 특정 함수에 권한 추가

 

mysql> GRANT EXECUTE ON xxxxDB.fn_xxxxxxxx to 'testapp'@'%';
ERROR 1144 (42000): Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used
/* 함수인데 왜 할당이 안되는것일까? */


mysql> GRANT EXECUTE ON FUNCTION xxxxDB.fn_xxxxxxxx to 'testapp'@'%';
Query OK, 0 rows affected (0.03 sec)
/* 실행대상이 ON FUNCTION 임을 명시해줘야 함 */


mysql> flush privileges;
Query OK, 0 rows affected (0.03 sec)



2-2) 전역권한 추가

 

mysql> GRANT EXECUTE ON xxxxDB.* to 'testapp'@'%';
Query OK, 0 rows affected (0.04 sec)
/* 전역권한이라 DB스키마명만 명시하고 나머지를 *로 주면 권한추가가 가능하다는 것을 확인함 */


mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)

 


3.   권한 삭제  (추가했으면 삭제도 해봐야지)

 

mysql> REVOKE SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON xxxxDB.TB_TEMP_BACKUP from 'testapp'@'%';
Query OK, 0 rows affected (0.03 sec)


mysql> flush privileges;
Query OK, 0 rows affected (0.03 sec)

 

REVOKE로 권한삭제가 가능한데 GRANT 명령어와 차이는 TO FROM 

끝.

반응형
블로그 이미지

dung beetle

취미는 데이터 수집 직업은 MYSQL과 함께 일하는 DBA의 소소한 일상 이야기

,