MySQL 의 긴 사무 예시 상세 설명
'입문 MySQL'시 리 즈 는 이미 끝 났 습 니 다.앞으로 제 글 은 MySQL 을 위주 로 하고 최근 에 업무 와 학습 과정 에서 만난 장면 이나 자신의 깨 달 음 을 기록 할 것 입 니 다.후속 적 인 글 은 그렇게 일관성 이 없 을 수도 있 지만 많은 응원 을 바 랍 니 다.본론 으로 돌아 가면 이 글 은 주로 MySQL 장 업무 와 관련 된 내용 을 소개 합 니 다.예 를 들 어 우리 가 시작 한 업무 가 제출 되 지 않 거나 스크롤 백 을 하지 않 으 면 어떻게 되 는 지,업무 대기 상황 이 발생 하면 어떻게 처리 해 야 하 는 지,이 글 은 답 을 드 리 겠 습 니 다.
주의:이 글 은 트 랜 잭 션 격 리 등급 과 관련 특성 에 초점 을 맞 추 지 않 습 니 다.장 사무 관련 위해 및 감시 처리 방법 을 소개 하 는 것 입 니 다.본 고 는 MySQL 5.7.23 버 전 을 바탕 으로 중복 읽 기(RR)격 리 단계 에서 실험 할 수 없다.
1.사무 란 무엇 인가
우선 우 리 는 긴 일이 무엇 인지 알 아야 한다.말 그대로 운영 시간 이 비교적 길 고 장시간 제출 되 지 않 은 사 무 를 큰 사무 라 고도 할 수 있다.이런 사 무 는 대량의 차단 과 잠 금 시간 을 초과 하여 주종 지연 을 초래 하기 쉬 우 므 로 가능 한 한 긴 사 무 를 사용 하지 않도록 해 야 한다.
다음 에 저 는 사무 와 아 날로 그 장 사 무 를 어떻게 시작 하 는 지 보 여 드 리 겠 습 니 다.
# stu_tb ,
mysql> show create table stu_tb\G
*************************** 1. row ***************************
Table: stu_tb
Create Table: CREATE TABLE `stu_tb` (
`increment_id` int(11) NOT NULL AUTO_INCREMENT COMMENT ' ',
`stu_id` int(11) NOT NULL COMMENT ' ',
`stu_name` varchar(20) DEFAULT NULL COMMENT ' ',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ' ',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ' ',
PRIMARY KEY (`increment_id`),
UNIQUE KEY `uk_stu_id` (`stu_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 COMMENT=' '
1 row in set (0.01 sec)
mysql> select * from stu_tb;
+--------------+--------+----------+---------------------+---------------------+
| increment_id | stu_id | stu_name | create_time | update_time |
+--------------+--------+----------+---------------------+---------------------+
| 1 | 1001 | from1 | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
| 2 | 1002 | dfsfd | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
| 3 | 1003 | fdgfg | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
| 4 | 1004 | sdfsdf | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
| 5 | 1005 | dsfsdg | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
| 6 | 1006 | fgd | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
| 7 | 1007 | fgds | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
| 8 | 1008 | dgfsa | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
+--------------+--------+----------+---------------------+---------------------+
8 rows in set (0.00 sec)
# , begin start transaction
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from stu_tb where stu_id = 1006 for update;
+--------------+--------+----------+---------------------+---------------------+
| increment_id | stu_id | stu_name | create_time | update_time |
+--------------+--------+----------+---------------------+---------------------+
| 6 | 1006 | fgd | 2019-09-15 14:27:34 | 2019-09-15 14:27:34 |
+--------------+--------+----------+---------------------+---------------------+
1 row in set (0.01 sec)
# , , , 。
2.어떻게 긴 사 무 를 찾 습 니까?업무 대기 문제 에 부 딪 혔 을 때,우리 가 먼저 해 야 할 일 은 실행 중인 사 무 를 찾 는 것 이다.information_schema.INNODB_TRX 표 에는 현재 innodb 내부 에서 실행 중인 트 랜 잭 션 정보 가 포함 되 어 있 습 니 다.이 표 에는 트 랜 잭 션 의 시작 시간 이 있 습 니 다.우 리 는 조금 만 연산 하면 트 랜 잭 션 의 실행 시간 을 얻 을 수 있 습 니 다.
mysql> select t.*,to_seconds(now())-to_seconds(t.trx_started) idle_time from INFORMATION_SCHEMA.INNODB_TRX t \G
*************************** 1. row ***************************
trx_id: 6168
trx_state: RUNNING
trx_started: 2019-09-16 11:08:27
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 3
trx_mysql_thread_id: 11
trx_query: NULL
trx_operation_state: NULL
trx_tables_in_use: 0
trx_tables_locked: 1
trx_lock_structs: 3
trx_lock_memory_bytes: 1136
trx_rows_locked: 2
trx_rows_modified: 0
trx_concurrency_tickets: 0
trx_isolation_level: REPEATABLE READ
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
trx_is_read_only: 0
trx_autocommit_non_locking: 0
idle_time: 170
결과 에서 idletime 은 계산 으로 생 긴 것 이자 업무 의 지속 시간 이다.하지만 사무의 trxquery 는 NUL 입 니 다.아무것도 실행 되 지 않 았 다 는 것 이 아 닙 니 다.한 사무 에 여러 개의 SQL 이 포함 되 어 있 을 수 있 습 니 다.SQL 이 실행 되면 더 이상 표시 되 지 않 습 니 다.현재 업무 가 실행 되 고 있 습 니 다.innodb 도 이 업무 의 후속 이 sql 이 있 는 지,언제 commt 가 있 는 지 모 릅 니 다.그래서 trxquery 는 의미 있 는 정 보 를 제공 할 수 없습니다.만약 우리 가 이 업무 가 실 행 된 SQL 을 보고 싶다 면,긴 사 무 를 죽 일 수 있 는 지 없 는 지 를 보고 싶다 면 어떻게 합 니까?우 리 는 다른 시스템 표 와 연합 하여 조회 할 수 있 습 니 다.구체 적 인 조회 SQL 은 다음 과 같 습 니 다.
mysql> select now(),(UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(a.trx_started)) diff_sec,b.id,b.user,b.host,b.db,d.SQL_TEXT from information_schema.innodb_trx a inner join
-> information_schema.PROCESSLIST b
-> on a.TRX_MYSQL_THREAD_ID=b.id and b.command = 'Sleep'
-> inner join performance_schema.threads c ON b.id = c.PROCESSLIST_ID
-> inner join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID;
+---------------------+----------+----+------+-----------+--------+-----------------------------------------------------+
| now() | diff_sec | id | user | host | db | SQL_TEXT |
+---------------------+----------+----+------+-----------+--------+-----------------------------------------------------+
| 2019-09-16 14:06:26 | 54 | 17 | root | localhost | testdb | select * from stu_tb where stu_id = 1006 for update |
+---------------------+----------+----+------+-----------+--------+-----------------------------------------------------+
상기 결과 중 diffsec 와 위 idletime 은 뜻 이 같 습 니 다.모두 이 업무 가 지속 되 는 초 수 를 대표 합 니 다.SQL_TEXT 는 이 업무 가 방금 실 행 된 SQL 을 표시 합 니 다.그러나 상기 문 구 는 마지막 으로 실 행 된 SQL 만 찾 을 수 있 습 니 다.우 리 는 한 업무 에 여러 개의 SQL 이 포함 되 어 있 을 수 있다 는 것 을 알 고 있 습 니 다.그러면 우 리 는 제출 되 지 않 은 업무 가 어떤 SQL 을 실 행 했 는 지 알 고 싶 습 니 다.만족 할 수 있 는 지,답 은 events 와 결합 하 는 것 입 니 다.statements_history 시스템 표 도 수 요 를 만족 시 킬 수 있 습 니 다.다음 문 구 는 이 업무 가 실 행 된 모든 SQL 을 조회 합 니 다.
mysql> select now(),(UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(a.trx_started)) diff_sec,b.id,b.user,b.host,b.db,d.SQL_TEXT from information_schema.innodb_trx a inner join
-> information_schema.PROCESSLIST b
-> on a.TRX_MYSQL_THREAD_ID=b.id and b.command = 'Sleep'
-> inner join performance_schema.threads c ON b.id = c.PROCESSLIST_ID
-> inner join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID;
+---------------------+----------+----+------+-----------+--------+-----------------------------------------------------+
| now() | diff_sec | id | user | host | db | SQL_TEXT |
+---------------------+----------+----+------+-----------+--------+-----------------------------------------------------+
| 2019-09-16 14:06:26 | 54 | 17 | root | localhost | testdb | select * from stu_tb where stu_id = 1006 for update |
+---------------------+----------+----+------+-----------+--------+-----------------------------------------------------+
상기 결과 에서 우 리 는 이 업무 가 처음부터 지금까지 실 행 된 모든 SQL 을 볼 수 있다.우리 가 이 업무 와 관련 된 정 보 를 모두 조회 한 후에 우 리 는 이 업무 가 다른 업무 에 영향 을 주지 않도록 죽 일 수 있 는 지 여 부 를 판단 할 수 있다.여기 서 조금 넓 혀 지면 긴 사무 가 막 히 거나 잠 금 현상 을 일 으 키 기 쉬 우 므 로 일반적인 상황 에서 우 리 는 먼저 sys.innodb 를 조회 할 수 있 습 니 다.lock_waits 보기 에서 트 랜 잭 션 차단 현상 이 있 는 지 확인 합 니 다:
# select * from stu_tb where stu_id = 1006 for update
# update stu_tb set stu_name = 'wang' where stu_id = 1006
mysql> select * from sys.innodb_lock_waits\G
*************************** 1. row ***************************
wait_started: 2019-09-16 14:34:32
wait_age: 00:00:03
wait_age_secs: 3
locked_table: `testdb`.`stu_tb`
locked_index: uk_stu_id
locked_type: RECORD
waiting_trx_id: 6178
waiting_trx_started: 2019-09-16 14:34:32
waiting_trx_age: 00:00:03
waiting_trx_rows_locked: 1
waiting_trx_rows_modified: 0
waiting_pid: 19
waiting_query: update stu_tb set stu_name = 'wang' where stu_id = 1006
waiting_lock_id: 6178:47:4:7
waiting_lock_mode: X
blocking_trx_id: 6177
blocking_pid: 20
blocking_query: NULL
blocking_lock_id: 6177:47:4:7
blocking_lock_mode: X
blocking_trx_started: 2019-09-16 14:18:44
blocking_trx_age: 00:15:51
blocking_trx_rows_locked: 2
blocking_trx_rows_modified: 0
sql_kill_blocking_query: KILL QUERY 20
sql_kill_blocking_connection: KILL 20
상기 결 과 는 막 힌 SQL 과 자물쇠 의 유형 을 보 여 주 었 고,더 강 한 것 은 세 션 을 죽 이 는 문구 도 나 왔 다 는 것 이다.그러나 세 션 실행 을 막 는 SQL 을 찾 지 못 했 습 니 다.더 자세 한 정 보 를 찾 으 려 면 다음 문 구 를 사용 하 십시오.
mysql> SELECT
-> tmp.*,
-> c.SQL_Text blocking_sql_text,
-> p.HOST blocking_host
-> FROM
-> (
-> SELECT
-> r.trx_state wating_trx_state,
-> r.trx_id waiting_trx_id,
-> r.trx_mysql_thread_Id waiting_thread,
-> r.trx_query waiting_query,
-> b.trx_state blocking_trx_state,
-> b.trx_id blocking_trx_id,
-> b.trx_mysql_thread_id blocking_thread,
-> b.trx_query blocking_query
-> FROM
-> information_schema.innodb_lock_waits w
-> INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
-> INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
-> ) tmp,
-> information_schema.PROCESSLIST p,
-> PERFORMANCE_SCHEMA.events_statements_current c,
-> PERFORMANCE_SCHEMA.threads t
-> WHERE
-> tmp.blocking_thread = p.id
-> AND t.thread_id = c.THREAD_ID
-> AND t.PROCESSLIST_ID = p.id \G
*************************** 1. row ***************************
wating_trx_state: LOCK WAIT
waiting_trx_id: 6180
waiting_thread: 19
waiting_query: update stu_tb set stu_name = 'wang' where stu_id = 1006
blocking_trx_state: RUNNING
blocking_trx_id: 6177
blocking_thread: 20
blocking_query: NULL
blocking_sql_text: select * from stu_tb where stu_id = 1006 for update
blocking_host: localhost
위의 결 과 는 더욱 뚜렷 해 보인다.우 리 는 차단 단 과 차단 단 업무 가 실 행 된 문 구 를 똑똑히 볼 수 있 고 차단 단 세 션 을 죽 일 수 있 는 지 확인 하 는 데 도움 이 된다.3.감시 장 사무
현실 업무 에서 우 리 는 긴 사 무 를 감시 하고 한도 값 을 정의 해 야 한다.예 를 들 어 30s 의 집행 시간 이 30s 를 초과 하 는 사 무 는 바로 긴 사무 이 고 기록 과 경 고 를 요구 하 며 관리자 에 게 처리 하 라 고 일 깨 워 야 한다.다음은 모니터링 스 크 립 트 를 드 리 겠 습 니 다.여러분 은 참고 하여 수요 에 따라 변경 하여 사용 할 수 있 습 니 다.
#!/bin/bash
# -------------------------------------------------------------------------------
# FileName: long_trx.sh
# Describe: monitor long transaction
# Revision: 1.0
# Date: 2019/09/16
# Author: wang
/usr/local/mysql/bin/mysql -N -uroot -pxxxxxx -e "select now(),(UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(a.trx_started)) diff_sec,b.id,b.user,b.host,b.db,d.SQL_TEXT from information_schema.innodb_trx a inner join
information_schema.PROCESSLIST b
on a.TRX_MYSQL_THREAD_ID=b.id and b.command = 'Sleep'
inner join performance_schema.threads c ON b.id = c.PROCESSLIST_ID
inner join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID;" | while read A B C D E F G H
do
if [ "$C" -gt 30 ]
then
echo $(date +"%Y-%m-%d %H:%M:%S")
echo "processid[$D] $E@$F in db[$G] hold transaction time $C SQL:$H"
fi
done >> /tmp/longtransaction.txt
간단히 말씀 드 리 지만 여기 서-lt 30 은 30 초 라 는 뜻 으로 30 초 만 넘 으 면 긴 사무 로 인정 되 며 실제 수요 에 따라 사용자 정의 할 수 있 습 니 다.이 스 크 립 트 를 정시 작업 에 추가 하면 실행 할 수 있 습 니 다.요약:
본 고 는 주로 장 사무 와 관련 된 내용 을 소개 하고 장 사 무 를 어떻게 찾 는 지,장 사 무 를 어떻게 처리 하 는 지,장 사 무 를 어떻게 감시 하 는 지 를 소개 한다.일부 동료 들 은 아직 일 에 대한 이해 가 많 지 않 을 수도 있 으 니,이 글 이 당신 에 게 도움 이 되 기 를 바 랍 니 다.본 글 에 열거 한 조회 사무 관련 문구 가 비교적 많 기 때문에 다음 과 같이 요약 합 니 다.
#
select t.*,to_seconds(now())-to_seconds(t.trx_started) idle_time from INFORMATION_SCHEMA.INNODB_TRX t \G
# SQL
select now(),(UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(a.trx_started)) diff_sec,b.id,b.user,b.host,b.db,d.SQL_TEXT from information_schema.innodb_trx a inner join information_schema.PROCESSLIST b
on a.TRX_MYSQL_THREAD_ID=b.id and b.command = 'Sleep'
inner join performance_schema.threads c ON b.id = c.PROCESSLIST_ID
inner join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID;
# SQL
SELECT
ps.id 'PROCESS ID',
ps.USER,
ps.HOST,
esh.EVENT_ID,
trx.trx_started,
esh.event_name 'EVENT NAME',
esh.sql_text 'SQL',
ps.time
FROM
PERFORMANCE_SCHEMA.events_statements_history esh
JOIN PERFORMANCE_SCHEMA.threads th ON esh.thread_id = th.thread_id
JOIN information_schema.PROCESSLIST ps ON ps.id = th.processlist_id
LEFT JOIN information_schema.innodb_trx trx ON trx.trx_mysql_thread_id = ps.id
WHERE
trx.trx_id IS NOT NULL
AND ps.USER != 'SYSTEM_USER'
ORDER BY
esh.EVENT_ID;
#
select * from sys.innodb_lock_waits\G
#
SELECT
tmp.*,
c.SQL_Text blocking_sql_text,
p.HOST blocking_host
FROM
(
SELECT
r.trx_state wating_trx_state,
r.trx_id waiting_trx_id,
r.trx_mysql_thread_Id waiting_thread,
r.trx_query waiting_query,
b.trx_state blocking_trx_state,
b.trx_id blocking_trx_id,
b.trx_mysql_thread_id blocking_thread,
b.trx_query blocking_query
FROM
information_schema.innodb_lock_waits w
INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id
INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id
) tmp,
information_schema.PROCESSLIST p,
PERFORMANCE_SCHEMA.events_statements_current c,
PERFORMANCE_SCHEMA.threads t
WHERE
tmp.blocking_thread = p.id
AND t.thread_id = c.THREAD_ID
AND t.PROCESSLIST_ID = p.id \G
총결산이상 은 이 글 의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.여러분 의 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
MySQL에서 JSON 인덱싱 - aarondfrancis사람들은 종종 MySQL로 JSON을 인덱싱할 수 없다고 말하지만 완전히 정확하지는 않습니다. MySQL로 JSON 열을 인덱싱하는 것은 완전히 가능합니다! 사람들은 종종 MySQL로 JSON을 인덱싱할 수 없다고 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.