本文問題
- MySQL為什么要打開表?
- MySQL打開表對(duì)操作系統(tǒng)有什么影響,哪種存儲(chǔ)引擎有額外的影響?
- MySQL在什么情況下打開表,在什么情況下關(guān)閉表?
- MySQL表緩存相關(guān)的參數(shù)有哪些?都有什么作用?
- MySQL表緩存的釋放機(jī)制是怎樣的?
- 如何查看MySQL緩存的表的數(shù)量?
- 在什么情況下應(yīng)該增加表緩存?
- 如何查看當(dāng)前緩存了哪些表?
MySQL表的打開和關(guān)閉
MySQL是多線程的,因此可能有多個(gè)客戶端同時(shí)對(duì)同一個(gè)表進(jìn)行查詢,為了減少多個(gè)客戶端會(huì)話在同一個(gè)表上具有不同狀態(tài)的問題,并發(fā)的每個(gè)會(huì)話都會(huì)獨(dú)立的打開表。這樣會(huì)使用額外的內(nèi)存,但是通常可以提升性能。
為了減少會(huì)話間對(duì)表緩存的爭(zhēng)用,提高擴(kuò)展性,表緩存還可以被分區(qū)為多個(gè)小的緩存實(shí)例。對(duì)于DML操作,會(huì)話只需要鎖定它訪問的一個(gè)實(shí)例就可以執(zhí)行。DDL操作還是需要鎖定整個(gè)表緩存。
MySQL表的打開
在MySQL執(zhí)行查詢時(shí),會(huì)先打開并緩存表。
MyISAM表的特殊情況
對(duì)于MyISAM存儲(chǔ)引擎,每個(gè)打開的表都需要兩個(gè)文件描述符,一個(gè)用于數(shù)據(jù)文件,一個(gè)用于索引文件。當(dāng)一個(gè)表已經(jīng)打開后,再進(jìn)行打開只需要占用一個(gè)文件描述符,因?yàn)樗饕募枋龇谒芯€程之間共享。
對(duì)于使用分區(qū)的MyISAM表,打開表的每個(gè)分區(qū)都需要兩個(gè)文件描述符(當(dāng)MyISAM打開一個(gè)使用分區(qū)的表時(shí),無論是否使用分區(qū),都會(huì)打開表中的所有分區(qū)。)
MyISAM為每個(gè)并發(fā)的訪問打開表。這意味著,如果有兩個(gè)線程訪問同一個(gè)表,或者一個(gè)線程在同一個(gè)查詢中訪問兩次表(例如join
表本身),MyISAM表需要被打開兩次。每個(gè)打開表的請(qǐng)求都會(huì)占用表緩存的一個(gè)條目。
MySQL表的關(guān)閉
在以下情況下,MySQL關(guān)閉未使用的表并將他們從緩存中刪除
- 當(dāng)表緩存已滿并且線程嘗試打開一個(gè)不在緩存中的表的時(shí)候
- 當(dāng)表緩存中的內(nèi)容超過
table_open_cache
的數(shù)量并且一個(gè)在緩存中的表不再被任何線程使用的時(shí)候 - 當(dāng)發(fā)出表刷新語句的時(shí)候。表刷新語句包括
FLUSH TABLES
,mysqladmin flush-tables
,mysqladmin reflush
MySQL表緩存的清理機(jī)制
當(dāng)表緩存已滿的時(shí)候,使用以下機(jī)制釋放緩存
- 從最近最少使用的表開始,釋放當(dāng)前未使用的表
- 如果必須打開一個(gè)不在緩存中的表,但是緩存已滿并且沒有表可以釋放,則可以根據(jù)需要臨時(shí)擴(kuò)展緩存。
- 當(dāng)緩存處于臨時(shí)擴(kuò)展?fàn)顟B(tài)并且其中的表從使用中的狀態(tài)轉(zhuǎn)換為未使用的狀態(tài)時(shí),這個(gè)表會(huì)關(guān)閉并從緩存從釋放
表緩存相關(guān)的參數(shù)
table_open_cache
全局變量,可以動(dòng)態(tài)修改,默認(rèn)值2000
。取值范圍400-524288
所有線程打開的表的數(shù)量。
table_open_cache_instances
全局變量,不可以動(dòng)態(tài)修改,默認(rèn)值16
,取值范圍1-64
在16核或更高內(nèi)核數(shù)量的操作系統(tǒng)中,建議將值設(shè)置為8
或16
table_definition_cache
全局變量,可以動(dòng)態(tài)修改,默認(rèn)值-1
,表示自動(dòng)調(diào)節(jié)。取值范圍400-524288
默認(rèn)值 400 + ( table_open_cache / 2 )
,最高默認(rèn)值為2000
可以存儲(chǔ)在表定義緩存中的表定義(.frm
文件)數(shù)量。如果表的數(shù)量很多,可以增加該值來提升打開表的速度。表定義緩存使用較小的空間,并且不像表緩存一樣需要使用文件描述符。
表緩存相關(guān)的狀態(tài)
全局狀態(tài)
Open_files
當(dāng)前打開的文件數(shù)。只包括在數(shù)據(jù)庫級(jí)別打開的文件,不包括Socked
文件和管道文件,也不包過存儲(chǔ)引擎使用自己內(nèi)部函數(shù)打開的文件。
Opened_files
打開過的文件數(shù)。只計(jì)算通過my_open()
函數(shù)打開的文件數(shù)
全局+會(huì)話狀態(tài)
Open_tables
當(dāng)前打開的表數(shù)量
Opened_tables
打開過的表數(shù)量
Open_table_definitions
當(dāng)前打開的.frm
文件數(shù)量
Opened_table_definitions
打開過的.frm
文件數(shù)量
Table_open_cache_hits
表緩存命中次數(shù)
Table_open_cache_misses
表緩存未命中次數(shù)
Table_open_cache_overflows
表緩存溢出次數(shù)。就是在一個(gè)表打開或關(guān)閉后,一個(gè)緩存實(shí)例具有空白條目并且緩存實(shí)例實(shí)際大小大于緩存實(shí)例理論大小(table_open_cache/table_open_chche_instances)
的次數(shù)。
查看緩存的表
語句
SHOW OPEN TABLES
[{FROM | IN} db_name]
[LIKE 'pattern' | WHERE expr]
show open tables;
+--------------------+----------------+--------+-------------+
| Database | Table | In_use | Name_locked |
+--------------------+----------------+--------+-------------+
| performance_schema | session_status | 0 | 0 |
+--------------------+----------------+--------+-------------+
輸出說明
Database
庫名
Table
表名
In_use
對(duì)于該表的鎖或鎖請(qǐng)求數(shù)量(表級(jí)鎖)。
Name_locked
表名稱是否被鎖定。當(dāng)刪除表或者重命名表時(shí)會(huì)鎖定表名稱。
問題答案
- MySQL為什么要打開表?
為了提升性能。 - MySQL打開表對(duì)操作系統(tǒng)有什么影響,哪種存儲(chǔ)引擎有額外的影響?
打開表需要占用系統(tǒng)的文件描述符。對(duì)于MyISAM表,首次打開時(shí)需要兩個(gè)文件描述符,一個(gè)用于數(shù)據(jù)文件,一個(gè)用戶索引文件。當(dāng)MyISAM表第二次打開時(shí),只需要一個(gè)文件描述符,因?yàn)樗饕募谒芯€程之間共享。對(duì)于MyISAM分區(qū)表,在打開表時(shí)會(huì)打開所有表分區(qū),每個(gè)分區(qū)都需要兩個(gè)文件描述符。 - MySQL在什么情況下打開表,在什么情況下關(guān)閉表?
每個(gè)并發(fā)的查詢都會(huì)打開表。當(dāng)表緩存已滿但是需要緩存新表的時(shí)候,會(huì)關(guān)閉緩存中未使用的表并將它從緩存中刪除。也可以使用FLUSH TABLES
主動(dòng)關(guān)閉表。 - MySQL表緩存相關(guān)的參數(shù)有哪些?都有什么作用?
table_open_cache
定義了打開表的數(shù)量
table_open_cache_instances
定義了表緩存的實(shí)例數(shù)量。在進(jìn)行DML操作時(shí),只需要鎖定一個(gè)緩存實(shí)例
table_definition_cache
定義了.frm
文件的緩存數(shù)量 - MySQL表緩存的釋放機(jī)制是怎樣的?
在表緩存已滿但是需要緩存新的表的時(shí)候,首先檢查緩存中是否存在未在使用的表,如果存在,按照最近最少使用的原則關(guān)閉并釋放表,如果沒有未使用的表,臨時(shí)擴(kuò)展緩存并緩存新表,當(dāng)緩存中的表不再使用時(shí),對(duì)未使用的表進(jìn)行關(guān)閉和釋放,直到緩存的表數(shù)量小于等于open_table_cache
- 如何查看MySQL緩存的表的數(shù)量?
SHOW GLOBAL STATUS LIKE '%open%'
- 在什么情況下應(yīng)該增加表緩存?
在沒使用FLUSH TABLES
的情況下,發(fā)現(xiàn)Opened_tables
值很大。 - 如何查看當(dāng)前緩存了哪些表?
SHOW OPEN TABLES
還可以通過SHOW OPEN TABLES WHERE in_use>0
查看哪些表持有表鎖。