MySQL慢查詢?nèi)罩局械腖ock_time由來解析
慢查詢?nèi)罩?/h2>
經(jīng)常關(guān)注慢查詢?nèi)罩镜淖x者,和 Lock_time 應(yīng)該算是老相識(shí)了,大家對(duì)這位老相識(shí)了解有多少呢?
研究 Lock_time 之前,我對(duì)它的了解,僅限于它表示鎖等待時(shí)間。至于它包含哪些鎖等待時(shí)間、怎么計(jì)算得到的,我并不清楚。
所以,我一直有個(gè)困惑:為什么有些 SQL 執(zhí)行時(shí)間很長(zhǎng),Lock_time 卻很?。ɡ纾?.001 秒)?
今天我們就一起來看看,Lock_time 包含哪些鎖等待時(shí)間、以及是怎么計(jì)算得到的?
本文基于 MySQL 8.0.32 源碼,存儲(chǔ)引擎為 InnoDB。
1. 整體介紹
Lock_time 由兩部分相加得到:
- 表鎖等待時(shí)間,如果 SQL 中包含多個(gè)表,則是多個(gè)表鎖等待時(shí)間之和。
- 行鎖等待時(shí)間,如果 SQL 執(zhí)行過程中需要對(duì)多條記錄加鎖,則是多個(gè)行鎖等待時(shí)間之和。
對(duì) InnoDB 來說,DML、DQL 對(duì)記錄進(jìn)行增刪改查操作時(shí),如需加鎖,都是加行級(jí)別的共享鎖、排他鎖,而不加表級(jí)別的共享鎖、排他鎖。
共享鎖又稱作 S 鎖,排他鎖又稱作 X 鎖。
那么,InnoDB 有表級(jí)別的共享鎖、排他鎖嗎?
別說,還真有!
不過,不常有!
只有執(zhí)行 LOCK TABLES ... [READ | WRITE],并且系統(tǒng)變量 innodb_table_locks = 1、auto_commit = 0,InnoDB 才會(huì)加表級(jí)別的共享鎖、排他鎖。
從代碼注釋和官方文檔對(duì) innodb_table_locks
的介紹來看,執(zhí)行存儲(chǔ)過程和觸發(fā)器時(shí),InnoDB 也可能會(huì)加表級(jí)別的共享鎖、排他鎖,我們就不展開介紹了。
如果 InnoDB 加了表級(jí)別的共享鎖、排他鎖,Lock_time 包含表鎖等待時(shí)間,我們比較好理解。
如果我們執(zhí)行 DML、DQL,InnoDB 沒有加表級(jí)別的共享鎖、排他鎖,Lock_time 里還包含表鎖等待時(shí)間嗎?
這個(gè)問題,就得看用什么標(biāo)準(zhǔn)了:
- 嚴(yán)格來說,Lock_time 就不包含表鎖等待時(shí)間了。
- 不嚴(yán)格來說,Lock_time 還是包含表鎖等待時(shí)間的(InnoDB 采用了這個(gè)標(biāo)準(zhǔn))。
接下來,我們通過源碼,進(jìn)入表鎖、行鎖等待時(shí)間的實(shí)現(xiàn)邏輯,來一睹芳容。
2. 表鎖等待時(shí)間
我們先來看一下表鎖等待時(shí)間實(shí)現(xiàn)邏輯的堆棧:
|?>?mysql_execute_command(THD*,?bool)?sql/sql_parse.cc:4688 |?+?>?Sql_cmd_dml::execute(THD*)?sql/sql_select.cc:574 |?+?-?>?lock_tables(...)?sql/sql_base.cc:6899 |?+?-?x?>?mysql_lock_tables(...)?sql/lock.cc:337 |?+?-?x?=?>?lock_external(THD*,?TABLE**,?unsigned?int)?sql/lock.cc:393 |?+?-?x?=?|?>?handler::ha_external_lock(THD*,?int)?sql/handler.cc:7841 |?+?-?x?=?|?+?>?ha_innobase::external_lock(THD*,?int)?storage/innobase/handler/ha_innodb.cc:18869
Sql_cmd_dml::execute () 調(diào)用 lock_tables () 對(duì)多個(gè)表加鎖。
//?sql/sql_base.cc bool?lock_tables(THD?*thd,?Table_ref?*tables,?uint?count,?uint?flags)?{ ??... ??if?(!thd->locked_tables_mode)?{ ????... ????if?(!(thd->lock?= ??????????mysql_lock_tables(thd,?start,?(uint)(ptr?-?start),?flags))) ??????return?true; ????... ??} ??... }
lock_tables () 調(diào)用 mysql_lock_tables () 對(duì)多個(gè)表加鎖。
//?sql/lock.cc MYSQL_LOCK?*mysql_lock_tables(THD?*thd,?TABLE?**tables,?size_t?count, ??????????????????????????????uint?flags)?{ ??... ??//?記錄開始時(shí)間 ??ulonglong?lock_start_usec?=?my_micro_time(); ??... ??if?(sql_lock->table_count?&& ??????lock_external(thd,?sql_lock->table,?sql_lock->table_count))?{ ????/*?Clear?the?lock?type?of?all?lock?data?to?avoid?reusage.?*/ ????reset_lock_data_and_free(&sql_lock); ????goto?end; ??} ??... ??//?lock_external()?執(zhí)行完成之后 ??//?當(dāng)前時(shí)間減去開始時(shí)間 ??//?就是表鎖等待時(shí)間 ??ulonglong?lock_end_usec?=?my_micro_time(); ??thd->inc_lock_usec(lock_end_usec?-?lock_start_usec); ??... }
mysql_lock_tables () 調(diào)用 lock_external () 之前,先把當(dāng)前時(shí)間記錄下來,作為表鎖等待的開始時(shí)間。
然后調(diào)用 lock_external () 對(duì)多個(gè)表加鎖。
最后,調(diào)用 thd->inc_lock_usec () 把表鎖等待時(shí)間累加到 server 層線程對(duì)象(thd)的 m_lock_usec 屬性中。
//?sql/lock.cc static?int?lock_external(THD?*thd,?TABLE?**tables,?uint?count)?{ ??... ??//?循環(huán)?SQL?中的表 ??for?(i?=?1;?i?<=?count;?i++,?tables++)?{ ????assert((*tables)->reginfo.lock_type?>=?TL_READ); ????//?默認(rèn)鎖類型為寫鎖 ????//?對(duì)應(yīng)到?InnoDB?的鎖類型就是排他鎖(X) ????lock_type?=?F_WRLCK;?/*?Lock?exclusive?*/ ????//?如果以只讀方式打開表的數(shù)據(jù)文件(.ibd)或者 ????//?lock_type?大于等于?TL_READ(2)?并且 ????//?lock_type?小于等于?TL_READ_NO_INSERT(5) ????//?則說明是只讀操作,加讀鎖 ????//?對(duì)應(yīng)到?InnoDB?的鎖類型就是共享鎖(S) ????if?((*tables)->db_stat?&?HA_READ_ONLY?|| ????????((*tables)->reginfo.lock_type?>=?TL_READ?&& ?????????(*tables)->reginfo.lock_type?<=?TL_READ_NO_INSERT)) ??????lock_type?=?F_RDLCK; ????if?((error?=?(*tables)->file->ha_external_lock(thd,?lock_type)))?{ ??????//?ha_external_lock()?返回非?0?值 ??????//?說明執(zhí)行?ha_external_lock()?方法出現(xiàn)了錯(cuò)誤 ??????//?這里處理善后工作 ??????... ??????return?error; ????}?else?{ ??????(*tables)->db_stat?&=?~HA_BLOCK_LOCK; ??????(*tables)->current_lock?=?lock_type; ????} ??} ??return?0; }
lock_external () 會(huì)迭代 SQL 中的表,每迭代一個(gè)表,都調(diào)用 ha_external_lock () 對(duì)表進(jìn)行加鎖。
//?sql/handler.cc int?handler::ha_external_lock(THD?*thd,?int?lock_type)?{ ??... ??MYSQL_TABLE_LOCK_WAIT(PSI_TABLE_EXTERNAL_LOCK,?lock_type, ????{?error?=?external_lock(thd,?lock_type);?}) ??... }
handler::ha_external_lock () 調(diào)用表對(duì)應(yīng)存儲(chǔ)引擎的 external_lock () 方法。
對(duì) InnoDB 來說,調(diào)用的是 ha_innobase::external_lock()
,這個(gè)方法的代碼比較多,算是個(gè)大雜燴,可以分為三類:
加表級(jí)別的共享鎖、排他鎖。
把當(dāng)前迭代表所屬表空間的臟頁(yè),同步刷新到磁盤。
一些初始化邏輯(執(zhí)行快,花費(fèi)時(shí)間極少)。
ha_innobase::external_lock () 的執(zhí)行時(shí)間會(huì)計(jì)入表鎖等待時(shí)間,因?yàn)槠渲锌赡馨剿⑴K頁(yè)操作、執(zhí)行一些初始化邏輯花費(fèi)的時(shí)間,所以,表鎖等待時(shí)間并不純粹。
對(duì)需要加表鎖的 SQL 來說,表鎖等待時(shí)間包含兩部分:
加表級(jí)別的共享鎖、排他鎖的等待時(shí)間。
執(zhí)行一些初始化邏輯花費(fèi)的時(shí)間。
如果是 FLUSH TABLES ... WITH READ LOCK 語(yǔ)句,表鎖等待時(shí)間還包含:把其中涉及的表所屬表空間的臟頁(yè)同步刷新到磁盤所花費(fèi)的時(shí)間。
對(duì)不需要加表鎖的 SQL 來說,表鎖等待時(shí)間就是執(zhí)行 ha_innobase::external_lock () 中一些初始化邏輯花費(fèi)的時(shí)間。
我們來看看 ha_innobase::external_lock () 主要包含哪些代碼邏輯,對(duì)這部分細(xì)節(jié)不感興趣的讀者,可以跳過這個(gè)小節(jié)。
這個(gè)小節(jié)的代碼都來自于 ha_innobase::external_lock()
,文件路徑 storage/innobase/handler/ha_innodb.cc
。
update_thd(thd);
以上代碼,創(chuàng)建 InnoDB 的事務(wù)對(duì)象(trx_t),保存到 server 層的用戶線程對(duì)象(thd)中。
//?lock_type?==?F_WRLCK,意味著需要加寫鎖 //?這里用于表示需要記錄?binlog if?(lock_type?==?F_WRLCK?&& ????//?表示不支持?STATEMENT?格式的?binlog ????//?table_flags()?方法會(huì)判斷事務(wù)隔離級(jí)別 ????!(table_flags()?&?HA_BINLOG_STMT_CAPABLE)?&& ????//?系統(tǒng)變量?binlog_format?=?STATEMENT ????//?表示用戶需要記錄?STATEMENT?格式的?binlog ????thd_binlog_format(thd)?==?BINLOG_FORMAT_STMT?&& ????//?表示需要為當(dāng)前連接指定的數(shù)據(jù)庫(kù)記錄?binlog ????//?use?<db>?或者連接數(shù)據(jù)庫(kù)時(shí)指定了數(shù)據(jù)庫(kù) ????thd_binlog_filter_ok(thd)?&& ????//?表示當(dāng)前執(zhí)行的?SQL?會(huì)產(chǎn)生?ROW?格式的?binlog ????thd_sqlcom_can_generate_row_events(thd))?{ ??bool?skip?=?false; ??... ??if?(!skip)?{ ????... ????return?HA_ERR_LOGGING_IMPOSSIBLE; ??} }
上面代碼的判斷條件有點(diǎn)多,我們用一句話來概括一下代碼邏輯:
事務(wù)隔離級(jí)別為 READ_UNCOMMITTED
、READ_COMMITTED
時(shí),如果 SQL 會(huì)產(chǎn)生 ROW
格式的 binlog,而用戶設(shè)置系統(tǒng)變量 binlog_format 的值為 STATEMENT
,要求記錄 STATEMENT 格式的 binlog,ha_innobase::external_lock () 會(huì)返回 HA_ERR_LOGGING_IMPOSSIBLE
,因?yàn)?MySQL 無(wú)法處理這樣矛盾的場(chǎng)景。
if?(lock_type?==?F_WRLCK)?{ ??/*?If?this?is?a?SELECT,?then?it?is?in?UPDATE?TABLE?... ??or?SELECT?...?FOR?UPDATE?*/ ??m_prebuilt->select_lock_type?=?LOCK_X; ??m_stored_select_lock_type?=?LOCK_X; }
InnoDB 讀取記錄時(shí),會(huì)根據(jù) m_prebuilt->select_lock_type
的值確定是否加行鎖
、加共享鎖還是排他鎖。
lock_type 等于 F_WRLCK,表示 server 層要求加寫鎖,對(duì)應(yīng)到 InnoDB 的鎖類型,就是排他鎖,設(shè)置加鎖類型為 LOCK_X。
if?(lock_type?==?F_RDLCK)?{ ??... ??//?如果當(dāng)前表是數(shù)據(jù)字典表 ??//?或者被標(biāo)識(shí)為不需要加鎖(no_read_locking?=?true) ??//?設(shè)置加鎖類型為?LOCK_NONE ??if?(m_prebuilt->table->is_dd_table?||?m_prebuilt->no_read_locking)?{ ????m_prebuilt->select_lock_type?=?LOCK_NONE; ????m_stored_select_lock_type?=?LOCK_NONE; ??//?如果事務(wù)隔離級(jí)別是可串行化 ??}?else?if?(trx->isolation_level?==?TRX_ISO_SERIALIZABLE?&& ????//?并且當(dāng)前?SQL?還沒有確定加鎖類型 ????m_prebuilt->select_lock_type?==?LOCK_NONE?&& ????//?并且當(dāng)前事務(wù)需要手動(dòng)提交 ????thd_test_options(thd,?OPTION_NOT_AUTOCOMMIT?|?OPTION_BEGIN))?{ ????//?設(shè)置加鎖類型為共享鎖 ????m_prebuilt->select_lock_type?=?LOCK_S; ????m_stored_select_lock_type?=?LOCK_S; ??}?else?{ ????//?Retain?value?set?earlier?for?example?via?store_lock() ????//?which?is?LOCK_S?or?LOCK_NONE ????ut_ad(m_prebuilt->select_lock_type?==?LOCK_S?|| ??????????m_prebuilt->select_lock_type?==?LOCK_NONE); ??} }
lock_type 等于 F_RDLCK,表示 server 層要求加讀鎖,對(duì)應(yīng)到 InnoDB 的鎖類型,就是共享鎖,分兩種情況設(shè)置 InnoDB 的加鎖類型:
- 對(duì)于 ACL 表,
m_prebuilt->no_read_locking
會(huì)被設(shè)置為 true,表示讀取記錄時(shí)不加鎖
。 - 如果事務(wù)隔離級(jí)別是可串行化,并且當(dāng)前事務(wù)需要手動(dòng)執(zhí)行 COMMIT 語(yǔ)句提交,以及還沒有確定讀取該表記錄時(shí)加什么類型的行鎖,設(shè)置 InnoDB 加鎖類型為
共享鎖
。
ACL 表用于訪問權(quán)限控制,包含如下這些表:
user
db
tables_priv
columns_priv
procs_priv
proxies_priv
role_edges
default_roles
global_grants
password_history
switch?(m_prebuilt->table->quiesce)?{ ??case?QUIESCE_START: ????/*?Check?for?FLUSH?TABLE?t?WITH?READ?LOCK;?*/ ????if?(!srv_read_only_mode?&&?sql_command?==?SQLCOM_FLUSH?&& ????????lock_type?==?F_RDLCK)?{ ??????... ??????row_quiesce_table_start(m_prebuilt->table,?trx); ??????... ????} ????break; ??... }
只有執(zhí)行 FLUSH TABLES ... WITH READ LOCK 語(yǔ)句時(shí),才會(huì)命中代碼中的 case 分支。
row_quiesce_table_start () 會(huì)調(diào)用 buf_LRU_flush_or_remove_pages()
,并把當(dāng)前加表鎖的表所屬表空間對(duì)象傳給該方法,表示把該表空間的臟頁(yè)刷新到磁盤。
3. 行鎖等待時(shí)間
我們先來看看對(duì)一條記錄加行鎖的等待時(shí)間是怎么計(jì)算的。
InnoDB 讀取一條記錄時(shí),如需加行鎖,會(huì)調(diào)用 sel_set_rec_lock () 進(jìn)行加鎖。
如果其它事務(wù)持有該記錄的行鎖,sel_set_rec_lock()
會(huì)返回 DB_LOCK_WAIT,row_search_mvcc()
調(diào)用 row_mysql_handle_errors () 處理鎖等待邏輯。
row_mysql_handle_errors () 調(diào)用 lock_wait_suspend_thread()
,行鎖等待邏輯由這個(gè)方法實(shí)現(xiàn)。
//?storage/innobase/lock/lock0wait.cc void?lock_wait_suspend_thread(que_thr_t?*thr)?{ ??srv_slot_t?*slot; ??trx_t?*trx; ??//?聲明變量,用于保存行鎖等待的開始時(shí)間 ??std::chrono::steady_clock::time_point?start_time; ??... ??if?(thr->lock_state?==?QUE_THR_LOCK_ROW)?{ ????srv_stats.n_lock_wait_count.inc(); ????srv_stats.n_lock_wait_current_count.inc(); ????//?設(shè)置行鎖等待的開始時(shí)間 ????start_time?=?std::chrono::steady_clock::now(); ??} ??... ??//?等待行鎖 ??os_event_wait(slot->event); ??... ??//?運(yùn)行到這里,有兩種情況: ??//?1.?鎖等待超時(shí) ??//?2.?已經(jīng)獲取到行鎖 ??if?(thr->lock_state?==?QUE_THR_LOCK_ROW)?{ ????//?用當(dāng)前時(shí)間減去行鎖等待的開始時(shí)間 ????//?就是一條記錄的行鎖等待時(shí)間 ????const?auto?diff_time?=?std::chrono::steady_clock::now()?-?start_time; ????... ????/*?Record?the?lock?wait?time?for?this?thread?*/ ????//?累加線程的行鎖等待時(shí)間 ????//?保存到?mysql_thd?線程中 ????//?mysql_thd?是?server?層的線程 ????thd_set_lock_wait_time(trx->mysql_thd,?diff_time); ????... ??} ??... }
從上面代碼可以看到,計(jì)算一條記錄的行鎖等待時(shí)間,邏輯比較簡(jiǎn)單:
先保存當(dāng)前行鎖等待的開始時(shí)間,獲取到行鎖或等待行鎖超時(shí)之后,再用當(dāng)前時(shí)間減去開始時(shí)間,就得到了一條記錄的行鎖等待時(shí)間。
4. 累計(jì)時(shí)間
一滴水的夢(mèng)想是終有一天能夠匯入大海。
表鎖、行鎖等待時(shí)間的歸宿是累加起來,最終成為 lock_time,這個(gè)過程是通過調(diào)用 thd_set_lock_wait_time()
實(shí)現(xiàn)的。
//?storage/innobase/handler/ha_innodb.cc void?thd_set_lock_wait_time(THD?*thd, ????????????????????????????std::chrono::steady_clock::duration?value)?{ ??if?(thd)?{ ????thd_storage_lock_wait( ????????thd, ????????std::chrono::duration_cast<std::chrono::microseconds>(value).count()); ??} }
thd_set_lock_wait_time () 調(diào)用 thd_storage_lock_wait()
累加表鎖、行鎖等待時(shí)間。
//?sql/sql_thd_api.cc void?thd_storage_lock_wait(MYSQL_THD?thd,?long?long?value)?{ ??thd->inc_lock_usec(value); }
真正干活的是 THD::inc_lock_usec () 方法。
//?sql/sql_class.cc void?THD::inc_lock_usec(ulonglong?lock_usec)?{ ??m_lock_usec?+=?lock_usec; ??MYSQL_SET_STATEMENT_LOCK_TIME(m_statement_psi,?m_lock_usec); }
server 層每獲取到一個(gè)表鎖,都會(huì)調(diào)用 thd_set_lock_wait_time()
,累加表鎖等待時(shí)間。
最終會(huì)調(diào)用 THD::inc_lock_usec () 把表鎖等待時(shí)間累加到 server 層的線程對(duì)象 thd 的 m_lock_usec 屬性中。
InnoDB 每獲取到一條記錄的行鎖,或者行鎖等待超時(shí),都會(huì)調(diào)用 thd_set_lock_wait_time()
,累加行鎖等待時(shí)間。
最終會(huì)調(diào)用 THD::inc_lock_usec () 把行鎖等待時(shí)間累加到 server 層的線程對(duì)象 thd 的 m_lock_usec 屬性中。
5. lock_time
SQL 執(zhí)行完成之后,dispatch_command () 調(diào)用 log_slow_statement () 記錄慢查詢到文件中。
log_slow_statement () 也不是真正干活的,經(jīng)過多級(jí),最終調(diào)用 Query_logger::slow_log_write () 記錄慢查詢到文件中。
//?sql/log.cc bool?Query_logger::slow_log_write(THD?*thd,?const?char?*query, ??????????????????????????????????size_t?query_length,?bool?aggregate, ??????????????????????????????????ulonglong?lock_usec,?ulonglong?exec_usec)?{ ??... ??if?(aggregate)?{ ????query_utime?=?exec_usec; ????lock_utime?=?lock_usec; ??}?else?if?(thd->start_utime)?{ ????query_utime?=?(current_utime?-?thd->start_utime); ????lock_utime?=?thd->get_lock_usec(); ??}?else?{ ????query_utime?=?0; ????lock_utime?=?0; ??} ??... ??bool?error?=?false; ??for?(Log_event_handler?**current_handler?=?slow_log_handler_list; ???????*current_handler;)?{ ????error?|=?(*current_handler++)->log_slow( ???????????????thd,?current_utime, ???????????????(thd->start_time.tv_sec?*?1000000ULL)?+ ???????????????thd->start_time.tv_usec, ???????????????user_host_buff,?user_host_len,?query_utime, ???????????????lock_utime,?is_command,?query,?query_length); ??} ??... }
Query_logger::slow_log_write () 被調(diào)用時(shí),參數(shù) aggregate
的值都是 false,上面代碼不會(huì)進(jìn)入 if (aggregate)
分支。
if (thd->start_utime)
分支,lock_utime = thd->get_lock_usec (),從當(dāng)前線程對(duì)象(thd)中獲取之前累加的表鎖、行鎖等待時(shí)間。
然后,調(diào)用 log_slow () 記錄慢查詢到文件中。
//?sql/log.cc bool?Log_to_file_event_handler::log_slow( ????THD?*thd,?ulonglong?current_utime,?ulonglong?query_start_utime, ????const?char?*user_host,?size_t?user_host_len,?ulonglong?query_utime, ????ulonglong?lock_utime,?bool?is_command,?const?char?*sql_text, ????size_t?sql_text_len)?{ ??if?(!mysql_slow_log.is_open())?return?false; ??Silence_log_table_errors?error_handler; ??thd->push_internal_handler(&error_handler); ??bool?retval?=?mysql_slow_log.write_slow( ??????thd,?current_utime,?query_start_utime,?user_host,?user_host_len, ??????query_utime,?lock_utime,?is_command,?sql_text,?sql_text_len); ??thd->pop_internal_handler(); ??return?retval; }
Log_to_file_event_handler::log_slow () 最終調(diào)用 mysql_slow_log.write_slow () 記錄慢查詢到文件中。
//?sql/log.cc bool?File_query_log::write_slow(...)?{ ??... ??if?(!thd->copy_status_var_ptr)?{ ????if?(my_b_printf(&log_file, ????????"#?Query_time:?%s??Lock_time:?%s" ????????"?Rows_sent:?%lu??Rows_examined:?%lu\n", ????????query_time_buff,?lock_time_buff, ????????(ulong)thd->get_sent_row_count(), ????????(ulong)thd->get_examined_row_count())?==?(uint)-1) ??????goto?err;?/*?purecov:?inspected?*/ ??} ??... }
經(jīng)??绰樵?nèi)罩镜淖x者,想必對(duì)這 2 行會(huì)非常熟悉:
Query_time: %s Lock_time: %s
Rows_sent: %lu Rows_examined: %lu
其中的 Lock_time 就是本文的主題,介紹到這里,總算是和文章標(biāo)題遙相呼應(yīng)上了。
6. 總結(jié)
Lock_time 由表鎖、行鎖等待時(shí)間相加得到。
表鎖等待時(shí)間并不純粹,其中包含執(zhí)行一些初始化操作花費(fèi)的時(shí)間。
對(duì) FLUSH TABLES ... WITH READ LOCK 語(yǔ)句來說,還包含把其中涉及的表所屬表空間的臟頁(yè)同步刷新到磁盤所花費(fèi)的時(shí)間。
行鎖等待時(shí)間很純粹,就是多條記錄的行鎖等待時(shí)間之和,或者一條記錄的行鎖等待時(shí)間。
以上就是mysql慢查詢?nèi)罩局蠰ock_time的由來解析的詳細(xì)內(nèi)容,更多關(guān)于慢查詢?nèi)罩綥ock_time的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- MySQL慢查詢?nèi)罩緎lowlog的具體使用
- 詳解MySQL的慢查詢?nèi)罩竞湾e(cuò)誤日志
- 怎樣快速開啟MySQL的慢查詢?nèi)罩?/a>
- MySQL通用查詢?nèi)罩竞吐樵內(nèi)罩救娣治?/a>
- MySQL慢查詢?nèi)罩境敿?xì)總結(jié)
- 深入了解MySQL中的慢查詢?nèi)罩?/a>
- MySQL優(yōu)化教程之慢查詢?nèi)罩緦?shí)踐
- MySQL 慢查詢?nèi)罩旧钊肜斫?/a>
- MySQL慢查詢?nèi)罩镜淖饔煤烷_啟
- MySQL 慢查詢?nèi)罩镜拈_啟與配置
- MySQL慢查詢?nèi)罩?Slow Query Log)的實(shí)現(xiàn)
相關(guān)文章
MySQL學(xué)習(xí)之日期函數(shù)的用法詳解
本文將學(xué)習(xí)MySQL的日期函數(shù),在前面章節(jié)的練習(xí)中,我們就利用過NOW()函數(shù)來獲取過當(dāng)前系統(tǒng)時(shí)間,用DATEDIFF函數(shù)來計(jì)算日期相差的天數(shù),接下來我們就系統(tǒng)的學(xué)習(xí)一下 日期函數(shù)2022-08-08MySQL數(shù)據(jù)庫(kù)學(xué)習(xí)之分組函數(shù)詳解
這篇文章主要為大家詳細(xì)介紹一下MySQL數(shù)據(jù)庫(kù)中分組函數(shù)的使用,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)MySQL有一定幫助,需要的可以參考一下2022-07-07Mysql數(shù)據(jù)庫(kù)的主從同步配置方式
這篇文章主要介紹了Mysql數(shù)據(jù)庫(kù)的主從同步配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04MySQL占用內(nèi)存較大與CPU過高測(cè)試與解決辦法
為了裝mysql環(huán)境測(cè)試,裝上后發(fā)現(xiàn)啟動(dòng)后MySQL占用內(nèi)存了很大,達(dá)8百多兆。網(wǎng)上搜索了一下,得到高人指點(diǎn)my.ini。再也沒見再詳細(xì)的了..只好打開my.ini逐行的啃,雖然英文差了點(diǎn),不過多少M(fèi)還是看得明的2018-03-03MySQL實(shí)戰(zhàn)窗口函數(shù)SQL分析班級(jí)學(xué)生考試成績(jī)及生活消費(fèi)
這篇文章主要為大家介紹了MySQL實(shí)戰(zhàn),利用窗口函數(shù)SQL來分析班級(jí)學(xué)生的考試成績(jī)及生活消費(fèi)的示例過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-10-10mysql事件之修改事件(ALTER EVENT)、禁用事件(DISABLE)、啟用事件(ENABLE)、事件重命名及數(shù)
這篇文章主要介紹了mysql事件之修改事件(ALTER EVENT)、禁用事件(DISABLE)、啟用事件(ENABLE)、事件重命名及數(shù)據(jù)庫(kù)事件遷移操作,詳細(xì)分析了mysql數(shù)據(jù)庫(kù)事件的修改、禁用、啟用、重命名、遷移等原理與操作技巧,需要的朋友可以參考下2019-12-12MySql總彈出mySqlInstallerConsole窗口的解決方法
這篇文章主要介紹了MySql總彈出mySqlInstallerConsole窗口的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09