有趣的 events_statements_current 表問題
* GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯系小編並注明來源。
什麼是events_statements_current
表
在GreatSQL中,PFS下有一張記憶體表: events_statements_current
,看到這個名稱"xxx_current",小白如我可能會認為這張表中的資料就是當前系統的活躍(active)語句。該表的描述如下(有部分省略):
mysql> desc events_statements_current;
+-------------------------+------------------------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+------------------------------------------------+------+-----+---------+-------+
| THREAD_ID | bigint unsigned | NO | PRI | NULL | |
| EVENT_ID | bigint unsigned | NO | PRI | NULL | |
| END_EVENT_ID | bigint unsigned | YES | | NULL | |
| EVENT_NAME | varchar(128) | NO | | NULL | |
| SOURCE | varchar(64) | YES | | NULL | |
| TIMER_START | bigint unsigned | YES | | NULL | |
| TIMER_END | bigint unsigned | YES | | NULL | |
| TIMER_WAIT | bigint unsigned | YES | | NULL | |
| LOCK_TIME | bigint unsigned | NO | | NULL | |
| SQL_TEXT | longtext | YES | | NULL | |
| DIGEST | varchar(64) | YES | | NULL | |
| DIGEST_TEXT | longtext | YES | | NULL | |
| CURRENT_SCHEMA | varchar(64) | YES | | NULL | |
...
| MYSQL_ERRNO | int | YES | | NULL | |
| RETURNED_SQLSTATE | varchar(5) | YES | | NULL | |
| MESSAGE_TEXT | varchar(128) | YES | | NULL | |
...
+-------------------------+------------------------------------------------+------+-----+---------+-------+
44 rows in set (0.01 sec)
直接使用當前語句表的問題
直接做個小實驗,終端1:
SELECT sleep(1);
終端2:
USE performance_schema;
-- 檢視最近使用者語句
SELECT s.thread_id, s.sql_text FROM events_statements_current s, threads t
WHERE s.thread_id = t.thread_id AND t.type = 'FOREGROUND';
輸出:
mysql> SELECT s.thread_id, s.sql_text FROM events_statements_current s, threads t WHERE s.thread_id = t.thread_id AND t.type = 'FOREGROUND';
+-----------+--------------------------------------------------------------------------------------------------------------------------------------+
| thread_id | sql_text |
+-----------+--------------------------------------------------------------------------------------------------------------------------------------+
| 58 | select sleep(1) |
| 1849 | SELECT s.thread_id, s.sql_text FROM events_statements_current s, threads t WHERE s.thread_id = t.thread_id AND t.type = 'FOREGROUND' |
+-----------+--------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)
反覆執行上述語句,發現終端1當前執行的語句都是:SELECT sleep(1)
,看起來有點像BUG呀 。
真的是這樣嗎? 來細看一下文件的定義:
The events_statements_current table contains current statement events. The table stores one row per thread showing the current status of the thread's most recent monitored statement event, so there is no system variable for configuring the table size.
發現了一些關鍵資訊: "showing the current status of the thread's most recent monitored statement event",也就是說:儲存的是執行緒最近被檢測到的語句事件,並非當前正在處於執行狀態的語句
獲取當前活躍的語句方法
為了瞭解這個問題的解決方案,來看看具體實現的程式碼:
void pfs_end_statement_vc(PSI_statement_locker *locker, void *stmt_da) {
PSI_statement_locker_state *state =
reinterpret_cast<PSI_statement_locker_state *>(locker);
...
if (state->m_discarded) {
return;
}
...
// storage/perfschema/pfs.cc:6462
if (flags & STATE_FLAG_TIMED) {
timer_end = get_statement_timer();
wait_time = timer_end - state->m_timer_start;
}
...
if (flags & STATE_FLAG_THREAD) {
...
if(flags & STATE_FLAG_EVENT) {
...
// storage/perfschema/pfs.cc:6528
pfs->m_timer_end = timer_end;
pfs->m_cpu_time = cpu_time;
pfs->m_end_event_id = thread->m_event_id;
...
}
}
說明,在語句執行結束的時候,PFS會更新記錄:
m_timer_end 執行結束時間 m_end_event_id 語句結束事件ID
繼續閱讀程式碼,發現除了在:pfs_start_statement_vc
中對該值進行初始化外,修改該值的程式碼僅有這一處,基本可以得出結論:m_timer_end > 0
或 m_end_event_id >0
代表語句執行已經結束。
整個簡易工具測一下:
. ./setenv
FOR i IN $(seq 1 1000000)
DO
mysql -h127.0.0.1 -P3306 -uroot <<EOF
USE performance_schema;
-- 列印所有的進行中使用者SQL(除了自身)
SELECT s.* FROM events_statements_current s, threads t WHERE s.thread_id = t.thread_id AND t.type = 'FOREGROUND' AND sql_text like '%FOREGROUND%' = FALSE AND s.end_event_id IS NULL \G
EOF
sleep 0.1 # 每0.1秒跑一下
DONE
執行結果:
*************************** 1. row ***************************
THREAD_ID: 15082
EVENT_ID: 127
END_EVENT_ID: NULL
EVENT_NAME: statement/sql/select
SOURCE: init_net_server_extension.cc:95
TIMER_START: 19879433851621000
TIMER_END: 19880288626029000
TIMER_WAIT: 854774408000
LOCK_TIME: 0
SQL_TEXT: select sleep(1), 3
...
將工具SQL替換成
-- 移除原來的 s.end_event_id is NULL
SELECT s.* FROM events_statements_current s, threads t
WHERE s.thread_id = t.thread_id AND t.type = 'FOREGROUND' AND sql_text like '%FOREGROUND%' = FALSE AND s.timer_end = 0 \G
再次執行:
## 真的是啥也沒有啊,真的是啥也沒有啊,
再仔細看看文件 (https://dev.mysql.com/doc/refman/5.7/en/performance-schema-events-statements-current-table.html):
TIMER_START, TIMER_END, TIMER_WAIT
Timing information for the event. The unit for these values is picoseconds (trillionths of a second).
The TIMER_START and TIMER_END values indicate when event timing started and ended. TIMER_WAIT is the event elapsed time (duration).
If an event has not finished, TIMER_END is the current timer value and TIMER_WAIT is the time elapsed so far (TIMER_END − TIMER_START).
重要資訊: 當事件沒有完成,TIMER_END會持續參考當前時間更新
與想象的很不一樣,無奈開啟原始碼,看看有什麼線索
//storage/perfschema/table_events_statements.cc:315(table_events_statements_common)
if (m_row.m_end_event_id == 0) {
timer_end = get_statement_timer();
} else {
timer_end = statement->m_timer_end;
}
換句話說:執行未結束時,statement->m_timer_end
的值確實是0,但是timer_end賦值用的是語句計時器的當前時間。
測試結論:events_statements_current
可以用於描述當前活躍語句,活躍這個條件可以使用:END_EVENT_ID IS NULL
來過濾。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2936856/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一個有趣的鎖問題
- 一個有趣的this指向問題
- 使用Hibernate、JPA、Lombok遇到的有趣問題Lombok
- Go記憶體架構,一個有趣的問題Go記憶體架構
- 有趣的路燈問題——按規律列印圖形
- VS開發C++Dll的一些有趣問題C++
- 有趣的ES:解決es返回結果數量限制問題
- mysql 刪表引出的問題MySql
- 一個有趣的問題: 如何用HashSet來儲存重複的字串?字串
- $RMQ$問題($ST$表)MQ
- 記一個有趣的數學題
- 一個有趣的問題, 你知道SqlDataAdapter中的Fill是怎麼實現的嗎SQLLDAAPT
- leetcode題解(查詢表問題)LeetCode
- 一道很有趣的拓撲題
- 分享一道有趣的 Leetcode 題目LeetCode
- 一道有趣的golang排錯題Golang
- [專題]網路 IO 高階篇:一次有趣的 Docker 網路問題排查原創Docker
- table表頭固定問題
- 資料庫表的唯一索引問題資料庫索引
- 如何分析報表效能問題
- Mysql 表名大小寫問題MySql
- 儲存過程訪問其他使用者的表的問題儲存過程
- 遇到一個建表時出現的問題
- 什麼是大報表?如何解決大報表的問題?
- 有趣的cssCSS
- mysql.user表的資料準確性問題MySql
- form表單按enter鍵自動提交的問題ORM
- 如何解決表單提交的中文亂碼問題
- mysql 5.7.11查詢分割槽表的一個問題MySql
- 有趣的前端程式設計題:攜程 2018 春招前端程式設計
- 資料結構——RMQ(ST表)問題資料結構MQ
- 資料庫表規範化問題資料庫
- interval 分割槽表clob預設表空間指定問題
- 有趣的科普書
- JasperReport報表生成工具的基本使用和常見問題
- 關於動態表單遇到的一些問題
- DataFrame儲存為hive表時的換行符問題Hive
- Spring MVC from 表單接收二維陣列的問題SpringMVC陣列