您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“怎么理解MySQL中的table_id”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
一 table_id 介紹
當(dāng)MySQL 開啟日志模式時(shí),binlog會(huì)記錄所有對數(shù)據(jù)庫的變更操作。binlog 分兩種模式 statement 模式和row 模式。
當(dāng)數(shù)據(jù)庫的binlog format 是statement 模式時(shí)
例子:數(shù)據(jù)庫中執(zhí)行 一條語句
root@rac2 [yangyi]> insert into t1 values(9);
Query OK, 1 row affected (0.00 sec)
root@rac2 [yangyi]> show binlog events in 'mysql-bin.000003';
+------------------+-----+-------------+-----------+-------------+----------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+-------------+-----------+-------------+----------------------------------------+
| mysql-bin.000003 | 4 | Format_desc | 2 | 106 | Server ver: 5.1.68-log, Binlog ver: 4 |
| mysql-bin.000003 | 106 | Query | 2 | 176 | BEGIN |
| mysql-bin.000003 | 176 | Query | 2 | 265 | use `yangyi`; insert into t1 values(8) |
| mysql-bin.000003 | 265 | Xid | 2 | 292 | COMMIT /* xid=12 */ |
| mysql-bin.000003 | 292 | Query | 2 | 369 | use `yangyi`; flush tables |
| mysql-bin.000003 | 369 | Query | 2 | 439 | BEGIN |
| mysql-bin.000003 | 439 | Query | 2 | 528 | use `yangyi`; insert into t1 values(9) |
| mysql-bin.000003 | 528 | Xid | 2 | 555 | COMMIT /* xid=15 */ |
+------------------+-----+-------------+-----------+-------------+----------------------------------------+
8 rows in set (0.00 sec)
binlog 的log event 記錄如下:
#140511 14:44:12 server id 2 end_log_pos 439 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1399790652/*!*/;
BEGIN
/*!*/;
# at 439
#140511 14:44:12 server id 2 end_log_pos 528 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1399790652/*!*/;
insert into t1 values(9)
/*!*/;
# at 528
#140511 14:44:12 server id 2 end_log_pos 555 Xid = 15
COMMIT/*!*/;
從日志分析來看 ,DML會(huì)記錄為原始的SQL,也就是記錄在QUERY_EVENT中。
當(dāng)數(shù)據(jù)庫的binlog format 是row模式時(shí)
執(zhí)行insert 操作
root@rac2 [yangyi]> insert into t1 values(6);
Query OK, 1 row affected (0.00 sec)
root@rac2 [yangyi]> show binlog events in 'mysql-bin.000002';
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
| mysql-bin.000002 | 4 | Format_desc | 2 | 106 | Server ver: 5.1.68-log, Binlog ver: 4 |
| mysql-bin.000002 | 106 | Query | 2 | 176 | BEGIN |
| mysql-bin.000002 | 176 | Table_map | 2 | 219 | table_id: 18 (yangyi.t1) |
| mysql-bin.000002 | 219 | Write_rows | 2 | 253 | table_id: 18 flags: STMT_END_F |
| mysql-bin.000002 | 253 | Xid | 2 | 280 | COMMIT /* xid=61 */ |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
5 rows in set (0.00 sec)
binlog中記錄的信息:
BEGIN
/*!*/;
# at 176
# at 219
#140511 14:31:43 server id 2 end_log_pos 219 Table_map: `yangyi`.`t1` mapped to number 18
#140511 14:31:43 server id 2 end_log_pos 253 Write_rows: table id 18 flags: STMT_END_F
BINLOG '
TxlvUxMCAAAAKwAAANsAAAAAABIAAAAAAAEABnlhbmd5aQACdDEAAQMAAQ==
TxlvUxcCAAAAIgAAAP0AAAAAABIAAAAAAAEAAf/+BgAAAA==
'/*!*/;
### INSERT INTO `yangyi`.`t1`
### SET
### @1=6 /* INT meta=0 nullable=1 is_null=0 */
# at 253
#140511 14:31:43 server id 2 end_log_pos 280 Xid = 61
COMMIT/*!*/;
從解析的binlog中可以看出row模式下,DML操作會(huì)記錄為:TABLE_MAP_EVENT+ROW_LOG_EVENT(包括WRITE_ROWS_EVENT ,UPDATE_ROWS_EVENT,DELETE_ROWS_EVENT).
為什么一個(gè)update在ROW模式下需要分解成兩個(gè)event:一個(gè)Table_map,一個(gè)Update_rows。我們想象一下,一個(gè)update如果更新了10000條數(shù)據(jù),那么對應(yīng)的表結(jié)構(gòu)信息是否需要記錄10000次?其實(shí)是對同一個(gè)表的操作,所以這里binlog只是記錄了一個(gè)Table_map用于記錄表結(jié)構(gòu)相關(guān)信息,而后面的Update_rows記錄了更新數(shù)據(jù)的行信息。他們之間是通過table_id來聯(lián)系的。
二 table_id 的特性
1 table_id 并不是固定的,它是當(dāng)表被載入內(nèi)存(table_definition_cache)時(shí),臨時(shí)分配的,是一個(gè)不斷增長的變量。
2 當(dāng)有新的table變更時(shí),在cache中沒有,就會(huì)觸發(fā)一次load table def的操作,此時(shí)就會(huì)在原先最后一次table_id基礎(chǔ)上+1,做為新的table def的id。
3 flush tables,之后對表的更新操作也會(huì)觸發(fā)table_id 的增長。
4 如果table def cache過小,就會(huì)出現(xiàn)頻繁的換入換出,從而導(dǎo)致table_id增長比較快。
例子
root@rac2 [yangyi]> show binlog events in 'mysql-bin.000002';
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
| mysql-bin.000002 | 4 | Format_desc | 2 | 106 | Server ver: 5.1.68-log, Binlog ver: 4 |
| mysql-bin.000002 | 106 | Query | 2 | 176 | BEGIN |
| mysql-bin.000002 | 176 | Table_map | 2 | 219 | table_id: 18 (yangyi.t1) |
| mysql-bin.000002 | 219 | Write_rows | 2 | 253 | table_id: 18 flags: STMT_END_F |
| mysql-bin.000002 | 253 | Xid | 2 | 280 | COMMIT /* xid=61 */ |
| mysql-bin.000002 | 280 | Query | 2 | 357 | use `yangyi`; flush tables |
| mysql-bin.000002 | 357 | Query | 2 | 427 | BEGIN |
| mysql-bin.000002 | 427 | Table_map | 2 | 470 | table_id: 19 (yangyi.t1) |
| mysql-bin.000002 | 470 | Write_rows | 2 | 504 | table_id: 19 flags: STMT_END_F |
| mysql-bin.000002 | 504 | Xid | 2 | 531 | COMMIT /* xid=65 */ |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
10 rows in set (0.00 sec)
三 table_id在主從復(fù)制過程中轉(zhuǎn)變
每一個(gè)dml操作表的信息都被會(huì)記錄table_mapping的hash數(shù)據(jù)結(jié)構(gòu)中,hash的key就是ulong型的table_id,hash的值就是TABLE*的數(shù)據(jù)結(jié)構(gòu)(包含了表的各種信息,包括數(shù)據(jù)庫名,表名,字段數(shù),字段類型等),通過set_table()方法來hash,通過get_table()方法來根據(jù)table_id獲得對應(yīng)的表信息。
當(dāng)主庫的日志傳遞到備庫時(shí),每一個(gè)log_event都是通過do_apply_event()方法來將event應(yīng)用到本地?cái)?shù)據(jù)庫中。在apply relay log中的event時(shí),do_apply_event()將ulong型的m_table_id(binlog記錄的table_id)賦值給RPL_TABLE_LIST結(jié)構(gòu)中的uint型的table_id。核心問題出現(xiàn)了: 如果binlog 中的table_id 的值大于max(uint),在變量傳遞是,就會(huì)發(fā)生截?cái)唷?/span>
而MySQL內(nèi)部使用set_table(table_id)構(gòu)造hash,使用get_table(m_table_id)從hash表中取值,在兩個(gè)階段用到的key因?yàn)榘l(fā)生了數(shù)據(jù)截?cái)?所以必然也就不能取到預(yù)期的值。也就是說之前用uint型的table_id構(gòu)建出來的key-value的hash對,用ulong型的m_table_id是無法查詢到的。
四 風(fēng)險(xiǎn)與解決
從第二,三點(diǎn)我們知道當(dāng)table_id 過快增長,會(huì)導(dǎo)致從庫應(yīng)用binlog無法解析到對應(yīng)的表,造成數(shù)據(jù)不一致的情況。
解決方法:
1 加大 table cache 的大小。
2 重啟主庫使table_id 歸0,缺點(diǎn) 成本比較高,出現(xiàn)此問題的時(shí)候,主備已經(jīng)不一致,線上環(huán)境 不能完成切換。
3 修改MySQL源碼,將 RPL_TABLE_LIST結(jié)構(gòu)中的uint型的table_id修改為ulong型 ,一勞永逸。
“怎么理解MySQL中的table_id”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。