MySQL 에서 제출 되 지 않 은 SQL 인 스 턴 스 를 찾 습 니 다.
--테스트 환경 데이터 준비(실험 환경 은 MySQL 8.0.18 커 뮤 니 티 버 전)
mysql> create table kkk(id int , name varchar(12));
Query OK, 0 rows affected (0.34 sec)
mysql> insert into kkk values(1, 'kerry');
Query OK, 1 row affected (0.01 sec)
mysql> insert into kkk values(2, 'jerry');
Query OK, 1 row affected (0.00 sec)
mysql> insert into kkk values(3, 'ken');
Query OK, 1 row affected (0.00 sec)
mysql>
mysql> create table t(a varchar(10));
Query OK, 0 rows affected (0.47 sec)
mysql> insert into t values('test');
Query OK, 1 row affected (0.00 sec)
세 션 창(ID=38 연결)에서 다음 SQL 을 실행 합 니 다.
mysql> select connection_id() from dual;
+-----------------+
| connection_id() |
+-----------------+
| 38 |
+-----------------+
1 row in set (0.00 sec)
mysql> set session autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> delete from kkk where id =1;
Query OK, 1 row affected (0.00 sec)
mysql>
다음 세 션 창(ID=39 연결)에서 SQL 실행
mysql> SELECT t.trx_mysql_thread_id
-> ,t.trx_id
-> ,t.trx_state
-> ,t.trx_tables_in_use
-> ,t.trx_tables_locked
-> ,t.trx_query
-> ,t.trx_rows_locked
-> ,t.trx_rows_modified
-> ,t.trx_lock_structs
-> ,t.trx_started
-> ,t.trx_isolation_level
-> ,p.time
-> ,p.user
-> ,p.host
-> ,p.db
-> ,p.command
-> FROM information_schema.innodb_trx t
-> INNER JOIN information_schema.processlist p
-> ON t.trx_mysql_thread_id = p.id
-> WHERE t.trx_state = 'RUNNING'
-> AND p.time > 4
-> AND p.command = 'Sleep'\G
*************************** 1. row ***************************
trx_mysql_thread_id: 38
trx_id: 7981581
trx_state: RUNNING
trx_tables_in_use: 0
trx_tables_locked: 1
trx_query: NULL
trx_rows_locked: 4
trx_rows_modified: 1
trx_lock_structs: 2
trx_started: 2020-12-03 15:39:37
trx_isolation_level: REPEATABLE READ
time: 23
user: root
host: localhost
db: MyDB
command: Sleep
1 row in set (0.00 sec)
위의 SQL 에서 실 행 된 SQL 을 찾 을 수 없 지만,사실은 MySQL 에서 제출 되 지 않 은 마지막 SQL 은 아래 스 크 립 트 를 통 해 정확하게 찾 을 수 있 습 니 다.다음 과 같다.
SELECT t.trx_mysql_thread_id AS connection_id
,t.trx_id AS trx_id
,t.trx_state AS trx_state
,t.trx_started AS trx_started
,TIMESTAMPDIFF(SECOND,t.trx_started, now()) AS "trx_run_time(s)"
,t.trx_requested_lock_id AS trx_requested_lock_id
,t.trx_operation_state AS trx_operation_state
,t.trx_tables_in_use AS trx_tables_in_use
,t.trx_tables_locked AS trx_tables_locked
,t.trx_rows_locked AS trx_rows_locked
,t.trx_isolation_level AS trx_isolation_level
,t.trx_is_read_only AS trx_is_read_only
,t.trx_autocommit_non_locking AS trx_autocommit_non_locking
,e.event_name AS event_name
,e.timer_wait / 1000000000000 AS timer_wait
,e.sql_text
FROM information_schema.innodb_trx t,
performance_schema.events_statements_current e,
performance_schema.threads c
WHERE t.trx_mysql_thread_id = c.processlist_id
AND e.thread_id = c.thread_id\G;
다음 캡 처 에서 보 듯 이:세 션 창(ID=38 연결)에서 다음 SQL 을 계속 실행 합 니 다."select*from t;"아래 와 같다
mysql> set session autocommit=0;
Query OK, 0 rows affected (0.01 sec)
mysql> delete from kkk where id =1;
Query OK, 1 row affected (0.00 sec)
mysql> select * from t;
+------+
| a |
+------+
| test |
+------+
1 row in set (0.00 sec)
mysql>
세 션 창(연결 ID=39)에서 다음 SQL 을 계속 실행 하면 마지막 으로 실 행 된 SQL 문 구 를 캡 처 할 수 있 습 니 다."select*from t"
mysql> SELECT t.trx_mysql_thread_id AS connection_id
-> ,t.trx_id AS trx_id
-> ,t.trx_state AS trx_state
-> ,t.trx_started AS trx_started
-> ,TIMESTAMPDIFF(SECOND,t.trx_started, now()) AS "trx_run_time(s)"
-> ,t.trx_requested_lock_id AS trx_requested_lock_id
-> ,t.trx_operation_state AS trx_operation_state
-> ,t.trx_tables_in_use AS trx_tables_in_use
-> ,t.trx_tables_locked AS trx_tables_locked
-> ,t.trx_rows_locked AS trx_rows_locked
-> ,t.trx_isolation_level AS trx_isolation_level
-> ,t.trx_is_read_only AS trx_is_read_only
-> ,t.trx_autocommit_non_locking AS trx_autocommit_non_locking
-> ,e.event_name AS event_name
-> ,e.timer_wait / 1000000000000 AS timer_wait
-> ,e.sql_text
-> FROM information_schema.innodb_trx t,
-> performance_schema.events_statements_current e,
-> performance_schema.threads c
-> WHERE t.trx_mysql_thread_id = c.processlist_id
-> AND e.thread_id = c.thread_id\G;
*************************** 1. row ***************************
connection_id: 38
trx_id: 7981581
trx_state: RUNNING
trx_started: 2020-12-03 15:39:37
trx_run_time(s): 237
trx_requested_lock_id: NULL
trx_operation_state: NULL
trx_tables_in_use: 0
trx_tables_locked: 1
trx_rows_locked: 4
trx_isolation_level: REPEATABLE READ
trx_is_read_only: 0
trx_autocommit_non_locking: 0
event_name: statement/sql/select
timer_wait: 0.0002
sql_text: select * from t
1 row in set (0.00 sec)
ERROR:
No query specified
또한 위의 SQL 은 제출 되 지 않 은 업무 가 마지막 으로 실 행 된 SQL 문 구 를 가 져 올 수 있 습 니 다.생산 환경 에서 하나의 업무 에서 하나의 SQL 문 구 를 가 져 올 수 있 는 것 이 아니 라 여러 개의 SQL 문장의 집합 입 니 다.제출 되 지 않 은 트 랜 잭 션 에서 실 행 된 모든 SQL 을 찾 으 려 면 어떻게 합 니까?사실 MySQL 에는 방법 이 있 습 니 다.다음 SQL 문 구 를 찾 거나
SELECT trx.trx_mysql_thread_id AS processlist_id
,sc.thread_id
,trx.trx_started
,TO_SECONDS(now())-TO_SECONDS(trx_started) AS trx_last_time
,pc1.user
,pc1.host
,pc1.db
,sc.SQL_TEXT AS current_sql_text
,sh.history_sql_test
FROM INFORMATION_SCHEMA.INNODB_TRX trx
INNER JOIN INFORMATION_SCHEMA.processlist pc1 ON trx.trx_mysql_thread_id=pc1.id
INNER JOIN performance_schema.threads th on th.processlist_id = trx.trx_mysql_thread_id
INNER JOIN performance_schema.events_statements_current sc ON sc.THREAD_ID = th.THREAD_ID
INNER JOIN (
SELECT thread_id AS thread_id, GROUP_CONCAT(SQL_TEXT SEPARATOR ';') AS history_sql_test
FROM performance_schema.events_statements_history
GROUP BY thread_id
) sh ON sh.thread_id = th.thread_id
WHERE trx_mysql_thread_id != connection_id()
AND TO_SECONDS(now())-TO_SECONDS(trx_started) >= 0 ;
그러나 이 두 SQL 은 문제 가 있 습 니 다.현재 연결 역사상 실 행 된 모든 SQL 을 찾 을 수 있 습 니 다.(물론 전 제 는 이 SQL 들 이 performance 에 저장 되 어 있다 는 것 입 니 다.schema.events_statements_history 표 에서),즉 이 SQL 은 제출 되 지 않 은 사무소 에서 실 행 된 스 크 립 트 를 조회 할 뿐만 아니 라 과거 SQL 스 크 립 트 도 많이 조회 할 수 있 습 니 다.예 를 들 어 이 세 션(연결)이전 업무 의 SQL 문 구 는 비교적 골 치 아 픈 문제 도 있 습 니 다.어떤 SQL 이 어떤 업무 에 대응 하 는 지 구분 하기 어렵 습 니 다.다른 정 보 를 빌려 선별 해 야 한다.시간 과 힘 이 비교적 많이 든다.다음 과 같이 캡 처 하여 보 여 줍 니 다.왜냐하면 informationschema.innodb_trx 시스템 테이블 에 업무 시작 시간 포함(trxstarted),다른 시스템 표 는 업무 와 관련 된 시간 이 없 으 며,permance 를 빌 릴 수 밖 에 없습니다.schema.events_statements_history 의 TIMERSTART 필드 에서 이벤트 의 SQL 이 실행 되 기 시작 하 는 시간 을 가 져 옵 니 다.이 시간 은 반드시 업무 의 시작 시간 보다 작 거나 같 을 것 입 니 다(trxstarted 시작 하 다그래서 이 돌파구 에서 제출 되 지 않 은 모든 SQL 을 찾 아 보 세 요.다음은 TIMERSTART 등의 필드 에 대한 상세 한 소개.
TIMER 에 대하 여START,TIMER_END,TIMER_WAIT 의 소 개 는 다음 과 같다.
TIMER_START,TIMER_END,TIMER_WAIT:사건 의 시간 정보.이 값 의 단 위 는 피 초(조 분 의 1 초)다.
TIMER_START 와 TIMEREND 값 은 이벤트 의 시작 시간 과 종료 시간 을 나 타 냅 니 다.
TIMER_WAIT 는 이벤트 수행 에 소요 되 는 시간(지속 시간)입 니 다.
이벤트 가 완료 되 지 않 으 면 TIMEREND 는 현재 시간,TIMERWAIT 가 지금까지 거 친 시간(TIMEREND - TIMER_START)。
감시 기기 배치 표 setupinstruments 에 대응 하 는 모니터 TIMED 필드 가 NO 로 설정 되 어 있 으 면 이 모니터 의 시간 정 보 를 수집 하지 않 습 니 다.그러면 이 사건 에 대해 수집 한 정보 기록 에 TIMERSTART,TIMER_END 와 TIMERWAIT 필드 값 은 모두 NULL 입 니 다.
테스트,오 랜 고생 끝 에 거의 완벽 한 SQL 을 만 들 었 습 니 다.
SELECT @dt_ts:=UNIX_TIMESTAMP(NOW());
SELECT
@dt_timer:=MAX(sh.TIMER_START)
FROM performance_schema.threads AS t
INNER JOIN performance_schema.events_statements_history AS sh
ON t.`THREAD_ID`=sh.`THREAD_ID`
WHERE t.PROCESSLIST_ID=CONNECTION_ID();
SELECT sh.current_schema AS database_name
,t.thread_id
,it.trx_mysql_thread_id AS connection_id
,it.trx_id
,sh.event_id
,it.trx_state
,REPLACE(REPLACE(REPLACE(sh.`SQL_TEXT`,'
',' '),'\r',' '),'\t',' ') AS executed_sql
,it.trx_started
,FROM_UNIXTIME(@dt_ts-CAST((@dt_timer-sh.TIMER_START)/1000000000000 AS SIGNED)) AS start_time
,FROM_UNIXTIME(@dt_ts-CAST((@dt_timer-sh.TIMER_END) /1000000000000 AS SIGNED)) AS end_time
,(sh.TIMER_END-sh.TIMER_START)/1000000000000 AS used_seconds
,sh.TIMER_WAIT/1000000000000 AS wait_seconds
,sh.LOCK_TIME/1000000000000 AS lock_seconds
,sh.ROWS_AFFECTED AS affected_rows
,sh.ROWS_SENT AS send_rows
FROM performance_schema.threads AS t
INNER JOIN information_schema.innodb_trx it ON it.trx_mysql_thread_id = t.processlist_id
INNER JOIN performance_schema.events_statements_history AS sh
ON t.`THREAD_ID`=sh.`THREAD_ID`
WHERE t.PROCESSLIST_ID IN (
SELECT
p.ID AS conn_id
FROM `information_schema`.`INNODB_TRX` t
INNER JOIN `information_schema`.`PROCESSLIST` p
ON t.trx_mysql_thread_id=p.id
WHERE t.trx_state='RUNNING'
AND p.COMMAND='Sleep'
AND p.TIME>2
)
AND sh.TIMER_START<@dt_timer
AND FROM_UNIXTIME(@dt_ts-CAST((@dt_timer-sh.TIMER_START)/1000000000000 AS SIGNED)) >=it.trx_started
ORDER BY it.trx_id ASC, sh.TIMER_START ASC;
제출 되 지 않 은 SQL 을 찾 을 수 있 습 니 다.간단 한 테스트 는 전혀 문제 가 없 으 며 제출 되 지 않 은 몇 개의 테스트 를 구성 하 는 것 도 OK 입 니 다.그러나 위의 SQL 은 세 개의 SQL 로 구성 되 어 있어 서 좀 어색 하 다.연 구 를 해 보 니 아래 SQL 로 개조 할 수 있다.
SELECT sh.current_schema AS database_name
,t.thread_id
,it.trx_mysql_thread_id AS connection_id
,it.trx_id
,sh.event_id
,it.trx_state
,REPLACE(REPLACE(REPLACE(sh.`SQL_TEXT`,'
',' '),'\r',' '),'\t',' ') AS executed_sql
,it.trx_started
,DATE_SUB(NOW(), INTERVAL (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='UPTIME') - sh.TIMER_START*10e-13 second) AS start_time
,DATE_SUB(NOW(), INTERVAL (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='UPTIME') - sh.TIMER_END*10e-13 second) AS end_time
,(sh.TIMER_END-sh.TIMER_START)/1000000000000 AS used_seconds
,sh.TIMER_WAIT/1000000000000 AS wait_seconds
,sh.LOCK_TIME/1000000000000 AS lock_seconds
,sh.ROWS_AFFECTED AS affected_rows
,sh.ROWS_SENT AS send_rows
FROM performance_schema.threads AS t
INNER JOIN information_schema.innodb_trx it ON it.trx_mysql_thread_id = t.processlist_id
INNER JOIN performance_schema.events_statements_history AS sh
ON t.`THREAD_ID`=sh.`THREAD_ID`
WHERE t.PROCESSLIST_ID IN (
SELECT
p.ID AS conn_id
FROM `information_schema`.`INNODB_TRX` t
INNER JOIN `information_schema`.`PROCESSLIST` p
ON t.trx_mysql_thread_id=p.id
WHERE t.trx_state='RUNNING'
AND p.COMMAND='Sleep'
AND p.TIME>2
)
AND sh.TIMER_START<(SELECT VARIABLE_VALUE*1000000000000 FROM performance_schema.global_status WHERE VARIABLE_NAME='UPTIME')
AND DATE_SUB(NOW(), INTERVAL (SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME='UPTIME') - sh.TIMER_START*10e-13 second) >=it.trx_started
ORDER BY it.trx_id ASC, sh.TIMER_START ASC;
주의:performanceschema.global_status 는 MySQL 5.7 로 도입 되 었 습 니 다.데이터베이스 가 MySQL 5.6 이면 INFORMATION 을 사용 할 수 있 습 니 다.SCHEMA.GLOBAL_STATUS SQL 의 performance 바 꾸 기schema.global_status그렇다면 이 SQL 은 완벽 할 까?네티즌 MSSQL 123 은 테스트 환경 에서 상기 SQL 에서 아무런 데이터 도 찾 을 수 없다 는 것 을 발견 했다.왜냐하면 FROMUNIXTIME(@dt_ts-CAST((@dt_timer-sh.TIMER_START)/1000000000000 AS SIGNED)) >=it.trx_started 는 데 이 터 를 걸 러 내 고 해당 하 는 trx 를 검사 합 니 다.started 값 이 start 보다 큽 니 다.time
-----------------------------------------------------------------------------------
그러면 같은 테스트 환경,격일 테스트 를 할 때 갑자기 위의 첫 번 째 SQL 이 정상 이 고 두 번 째 SQL 은 서로 다른 쓰기 로 인해 starttime 에 미세한 차이 가 있어 조회 결과 가 완전히 다르다(두 번 째 SQL 문 구 는 밀리초 까지 정확 하고 비교 할 때 편차 로 일부 데 이 터 를 걸 러 낸다)
------------------------------------------------------------------------------------------------------------------------------------------------
관련 문 서 를 검색 하여 TIMER 알 아 보기START 필드 값 에 변동 이나 편차 가 있 을 수 있 습 니 다.그러면 이 파동 이나 편차 가 조회 결과 에 영향 을 줄 수 있 습 니 다.아래 내용 은http://porthos.ist.utl.pt/docs/mySQL/performance-schema.html
Modifications to the setup_timers table affect monitoring immediately. Events already in progress may use the original timer for the begin time and the new timer for the end time. To avoid unpredictable results after you make timer changes, use TRUNCATE TABLE to reset Performance Schema statistics.
The timer baseline (“time zero”) occurs at Performance Schema initialization during server startup. TIMER_START and TIMER_END values in events represent picoseconds since the baseline. TIMER_WAIT values are durations in picoseconds.
Picosecond values in events are approximate. Their accuracy is subject to the usual forms of error associated with conversion from one unit to another. If the CYCLE timer is used and the processor rate varies, there might be drift. For these reasons, it is not reasonable to look at the TIMER_START value for an event as an accurate measure of time elapsed since server startup. On the other hand, it is reasonable to use TIMER_START or TIMER_WAIT values in ORDER BY clauses to order events by start time or duration.
The choice of picoseconds in events rather than a value such as microseconds has a performance basis. One implementation goal was to show results in a uniform time unit, regardless of the timer. In an ideal world this time unit would look like a wall-clock unit and be reasonably precise; in other words, microseconds. But to convert cycles or nanoseconds to microseconds, it would be necessary to perform a division for every instrumentation. Division is expensive on many platforms. Multiplication is not expensive, so that is what is used. Therefore, the time unit is an integer multiple of the highest possible TIMER_FREQUENCY value, using a multiplier large enough to ensure that there is no major precision loss. The result is that the time unit is “picoseconds.” This precision is spurious, but the decision enables overhead to be minimized.
Before MySQL 5.7.8, while a wait, stage, statement, or transaction event is executing, the respective current-event tables display the event with TIMER_START populated, but with TIMER_END and TIMER_WAIT set to NULL
그 중의 한 단락 의 내용 은 다음 과 같다.
이벤트 의 피 초 값 은 근사치 입 니 다.그들의 정확성 은 한 단위 에서 다른 단위 로 전환 하 는 것 과 관련 된 흔 한 오차 형식의 영향 을 받는다.CYCLE 타 이 머 를 사용 하고 프로세서 속도 가 바 뀌 면 편차 가 있 을 수 있 습 니 다.이러한 이유 로 사건 을 TIMERSTART 값 을 서버 가 시 작 된 이래 거 친 시간의 정확 한 도량 으로 보 는 것 은 불합리 하 다.한편,ORDER BY 자구 에 TIMER 을 사용 합 니 다.START 또는 TIMERWAIT 값 은 시작 시간 이나 지속 시간 에 따라 사건 을 정렬 하 는 것 이 합 리 적 입 니 다.
우 리 는 흔히 일 격 필 살 문 제 를 해결 하려 고 하지만 복잡 한 환경 과 통제 할 수 없 는 요소 로 인해 현실 은 흔히'은 탄 이 없다'는 잔혹 함 이다.TIMER 를 만나면START 의 파동 이나 편차 가 조회 결과 에 영향 을 미 칠 때 우 리 는 글 앞의 SQL 을 통 해 대량의 SQL 을 찾 은 다음 에 다른 필드 나 정 보 를 통 해 어떤 것 이 제출 되 지 않 은 SQL 인지 인공 적 으로 선별 해 야 한다.
참고 자료:
https://stackoverflow.com/questions/25607249/mysql-performance-schema-how-to-get-event-time-from-events-statements-current-ta
http://porthos.ist.utl.pt/docs/mySQL/performance-schema.html
https://dev.mysql.com/doc/refman/5.7/en/performance-schema-timing.html
https://dev.mysql.com/doc/refman/8.0/en/performance-schema-timing.html
여기에 MySQL 이 제출 되 지 않 은 사무 SQL 을 찾 아 냈 다 는 글 이 소개 되 었 습 니 다.더 많은 MySQL 이 제출 되 지 않 은 사무 SQL 내용 을 찾 아 냈 습 니 다.이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.