MySQL執(zhí)行狀態(tài)查看與分析過程
當(dāng)mysql出現(xiàn)性能問題時,一般會查看mysql的執(zhí)行狀態(tài),執(zhí)行命令: show processlist
各列的含義
列名 | 含義 |
---|---|
id | 一個標(biāo)識,你要kill一個語句的時候使用,例如 mysql> kill 207 |
user | 顯示當(dāng)前用戶,如果不是root,這個命令就只顯示你權(quán)限范圍內(nèi)的sql語句 |
host | 顯示這個語句是從哪個ip 的哪個端口上發(fā)出的,可用來追蹤出問題語句的用戶 |
db | 顯示這個進(jìn)程目前連接的是哪個數(shù)據(jù)庫 |
command | 顯示當(dāng)前連接的執(zhí)行的命令,一般就是休眠(sleep),查詢(query),連接(connect) |
time | 此這個狀態(tài)持續(xù)的時間,單位是秒 |
state | 顯示使用當(dāng)前連接的sql語句的狀態(tài),很重要的列,state只是語句執(zhí)行中的某一個狀態(tài),例如查詢,需要經(jīng)過copying to tmp table,Sorting result,Sending data等狀態(tài)才可以完成 |
info | 顯示這個sql語句,因?yàn)殚L度有限,所以長的sql語句就顯示不全,但是一個判斷問題語句的重要依據(jù) |
state 狀態(tài)值
參考官網(wǎng):MySQL :: MySQL 5.7 Reference Manual :: 8.14.3 General Thread States
狀態(tài)值 | 說明 |
---|---|
After create | 當(dāng)線程在創(chuàng)建表的函數(shù)結(jié)束時創(chuàng)建表(包括內(nèi)部臨時表)時,會發(fā)生這種情況。即使由于某些錯誤而無法創(chuàng)建表,也會使用此狀態(tài)。 |
altering table | 服務(wù)器正在執(zhí)行就地 ALTER TABLE。 |
Analyzing | 線程正在計(jì)算 MyISAM 表的鍵分布(例如,對于 ANALYZE TABLE )。 |
checking permissions | 線程正在檢查服務(wù)器是否具有執(zhí)行語句所需的特權(quán)。 |
Checking table | 線程正在執(zhí)行表檢查操作。 |
cleaning up | 線程已處理了一個命令,并準(zhǔn)備釋放內(nèi)存和重置某些狀態(tài)變量。 |
committing alter table to storage engine | 服務(wù)器已完成就地 ALTER TABLE 并正在提交結(jié)果。 |
closing tables | 該線程正在將已更改的表數(shù)據(jù)刷新到磁盤并關(guān)閉已使用的表。這應(yīng)該是一個快速的操作。如果沒有,請驗(yàn)證磁盤是否已滿,并且磁盤使用率是否很高。 |
converting HEAP to ondisk | 線程正在將內(nèi)部臨時表從 MEMORY 表轉(zhuǎn)換為磁盤上的表。 |
copy to tmp table | 線程正在處理 ALTER TABLE 語句。此狀態(tài)發(fā)生在創(chuàng)建具有新結(jié)構(gòu)的表之后,但在將行復(fù)制到其中之前。 對于處于此狀態(tài)的線程,性能架構(gòu)可用于獲取有關(guān)復(fù)制操作進(jìn)度的信息。請參見第25.12.5節(jié)“性能架構(gòu)階段事件表”。 |
Copying to group table | 如果語句具有不同的 ORDER BY 和 GROUP BY 條件,則按組對行進(jìn)行排序并將其復(fù)制到臨時表中。 |
Copying to tmp table | 服務(wù)器正在復(fù)制到內(nèi)存中的臨時表。 |
Copying to tmp table on disk | 服務(wù)器正在復(fù)制到磁盤上的臨時表。臨時結(jié)果集變得太大(請參見第8.4.4節(jié)"MySQL中的內(nèi)部臨時表使用")。因此,線程將臨時表從內(nèi)存中的格式更改為基于磁盤的格式以節(jié)省內(nèi)存。 |
Creating index | 線程正在為 MyISAM 表處理 ALTER TABLE ... ENABLE KEYS 。 |
Creating sort index | 線程正在處理使用內(nèi)部臨時表解析的 SELECT 。 |
creating table | 線程正在創(chuàng)建一個表。這包括創(chuàng)建臨時表。 |
Creating tmp table | 線程正在內(nèi)存或磁盤上創(chuàng)建臨時表。如果該表是在內(nèi)存中創(chuàng)建的,但后來被轉(zhuǎn)換為磁盤上的表,則該操作期間的狀態(tài)為 Copying to tmp table on disk 。 |
deleting from main table | 服務(wù)器正在執(zhí)行多表刪除的第一部分。它只從第一個表中刪除,并保存用于從其他(引用)表中刪除的列和偏移量。 |
deleting from reference tables | 服務(wù)器正在執(zhí)行多表刪除的第二部分,并從其他表中刪除匹配的行。 |
discard_or_import_tablespace | 線程正在處理 ALTER TABLE ... DISCARD TABLESPACE 或 ALTER TABLE ... IMPORT TABLESPACE 語句。 |
end | 這發(fā)生在結(jié)束時,但在清除 ALTER TABLE 、 CREATE VIEW 、 DELETE 、 INSERT 、 SELECT 或 UPDATE 語句之前。 對于 end 狀態(tài),可能會發(fā)生以下操作: 表中的數(shù)據(jù)更改后刪除查詢緩存項(xiàng) 將事件寫入二進(jìn)制日志 釋放內(nèi)存緩沖區(qū),包括Blob |
executing | 線程已開始執(zhí)行語句。 |
Execution of init_command | 線程正在執(zhí)行 init_command 系統(tǒng)變量值中的語句。 |
freeing items | 線程已執(zhí)行命令。在此狀態(tài)下執(zhí)行的某些項(xiàng)釋放涉及查詢緩存。這個狀態(tài)通常跟在 cleaning up 后面。 |
FULLTEXT initialization | 服務(wù)器正準(zhǔn)備執(zhí)行自然語言全文搜索。 |
init | 這發(fā)生在初始化 ALTER TABLE 、 DELETE 、 INSERT 、 SELECT 或 UPDATE 語句之前。服務(wù)器在此狀態(tài)下執(zhí)行的操作包括刷新二進(jìn)制日志、 InnoDB 日志和一些查詢緩存清理操作。 |
Killed | 有人向線程發(fā)送了一個 KILL 語句,它應(yīng)該在下次檢查kill標(biāo)志時中止。在MySQL中的每個主要循環(huán)中都檢查該標(biāo)志,但在某些情況下,線程可能仍然需要很短的時間才能死亡。如果線程被其他線程鎖定,則kill在其他線程釋放其鎖后立即生效。 |
logging slow query | 線程正在向慢速查詢?nèi)罩緦懭胝Z句。 |
login | 連接線程在客戶端成功通過身份驗(yàn)證之前的初始狀態(tài)。 |
manage keys | 服務(wù)器正在啟用或禁用表索引。 |
Opening tables | 線程正在嘗試打開一個表。這應(yīng)該是非??斓某绦颍怯惺裁醋柚勾蜷_。例如, ALTER TABLE 或 LOCK TABLE 語句可以在語句完成之前阻止打開表。同樣值得檢查的是,你的 table_open_cache 值是否足夠大。 |
optimizing | 服務(wù)器正在對查詢執(zhí)行初始優(yōu)化。 |
preparing | 此狀態(tài)發(fā)生在查詢優(yōu)化期間。 |
preparing for alter table | 服務(wù)器正在準(zhǔn)備執(zhí)行就地 ALTER TABLE 。 |
Purging old relay logs | 線程正在刪除不需要的中繼日志文件。 |
query end | 此狀態(tài)發(fā)生在處理查詢之后,但在 freeing items 狀態(tài)之前。 |
Receiving from client | 服務(wù)器正在閱讀來自客戶端的數(shù)據(jù)包。這個狀態(tài)在MySQL 5.7.8之前被稱為 Reading from net 。 |
Removing duplicates | 該查詢使用 SELECT DISTINCT 的方式使得MySQL無法在早期階段優(yōu)化不同的操作。因此,MySQL需要一個額外的階段來刪除所有重復(fù)的行,然后再將結(jié)果發(fā)送給客戶端。 |
removing tmp table | 線程在處理了一個 SELECT 語句后刪除了一個內(nèi)部臨時表。如果未創(chuàng)建臨時表,則不使用此狀態(tài)。 |
rename | 線程正在重命名表。 |
rename result table | 線程正在處理 ALTER TABLE 語句,已創(chuàng)建新表,并將其重命名以替換原始表。 |
Reopen tables | 線程獲得了表的鎖,但在獲得鎖后注意到底層表結(jié)構(gòu)發(fā)生了變化。它已經(jīng)釋放了鎖,關(guān)閉了表,并試圖重新打開它。 |
Repair by sorting | 修復(fù)代碼正在使用排序來創(chuàng)建索引。 |
Repair done | 線程已完成 MyISAM 表的多線程修復(fù)。 |
Repair with keycache | 修復(fù)代碼使用通過密鑰緩存逐個創(chuàng)建密鑰。這比 Repair by sorting 慢得多。 |
Rolling back | 線程正在回滾事務(wù)。 |
Saving state | 對于 MyISAM 表操作(如修復(fù)或分析),線程將新表狀態(tài)保存到 .MYI 文件頭。狀態(tài)包括諸如行數(shù)、 AUTO_INCREMENT 計(jì)數(shù)器和鍵分布等信息。 |
Searching rows for update | 線程執(zhí)行第一階段,在更新行之前查找所有匹配的行。如果 UPDATE 正在更改用于查找相關(guān)行的索引,則必須執(zhí)行此操作。 |
Sending data | 線程正在閱讀和處理 SELECT 語句的行,并將數(shù)據(jù)發(fā)送到客戶端。由于在此狀態(tài)期間發(fā)生的操作往往會執(zhí)行大量的磁盤訪問(讀?。?,因此它通常是給定查詢的生命周期中運(yùn)行時間最長的狀態(tài)。 |
Sending to client | 服務(wù)器正在向客戶端寫入數(shù)據(jù)包。這個狀態(tài)在MySQL 5.7.8之前被稱為 Writing to net 。 |
setup | 線程正在開始 ALTER TABLE 操作。 |
Sorting for group | 線程正在進(jìn)行排序以滿足 GROUP BY 。 |
Sorting for order | 線程正在進(jìn)行排序以滿足 ORDER BY 。 |
Sorting index | 該線程正在對索引頁進(jìn)行排序,以便在 MyISAM 表優(yōu)化操作期間進(jìn)行更有效的訪問。 |
Sorting result | 對于 SELECT 語句,這與 Creating sort index 類似,但適用于非臨時表。 |
starting | 語句執(zhí)行開始時的第一階段。 |
statistics | 服務(wù)器正在計(jì)算統(tǒng)計(jì)信息以制定查詢執(zhí)行計(jì)劃。如果線程長時間處于這種狀態(tài),則服務(wù)器可能正在磁盤綁定中執(zhí)行其他工作。 |
System lock | 該線程已調(diào)用 mysql_lock_tables() ,并且自那以后未更新線程狀態(tài)。這是一種非常普遍的狀態(tài),可能由于多種原因而發(fā)生。 例如,線程將請求或等待表的內(nèi)部或外部系統(tǒng)鎖。當(dāng) InnoDB 在執(zhí)行 LOCK TABLES 期間等待表級鎖時,可能會發(fā)生這種情況。如果這種狀態(tài)是由外部鎖請求引起的,并且您沒有使用多個訪問相同 MyISAM 表的mysqld服務(wù)器,則可以使用 --skip-external-locking 選項(xiàng)禁用外部系統(tǒng)鎖。但是,默認(rèn)情況下外部鎖定是禁用的,因此該選項(xiàng)可能沒有任何作用。對于 SHOW PROFILE ,這個狀態(tài)意味著線程正在請求鎖(而不是等待鎖)。 |
update | 線程準(zhǔn)備開始更新表。 |
Updating | 線程正在搜索要更新的行并正在更新它們。 |
updating main table | 服務(wù)器正在執(zhí)行多表更新的第一部分。它只更新第一個表,并保存用于更新其他(引用)表的列和偏移量。 |
updating reference tables | 服務(wù)器正在執(zhí)行多表更新的第二部分,并更新其他表中匹配的行。 |
User lock | 線程將請求或正在等待通過 GET_LOCK() 調(diào)用請求的咨詢鎖。對于 SHOW PROFILE ,這個狀態(tài)意味著線程正在請求鎖(而不是等待鎖)。 |
User sleep | 該線程已調(diào)用 SLEEP() 調(diào)用。 |
Waiting for commit lock | FLUSH TABLES WITH READ LOCK 正在等待提交鎖。 |
Waiting for global read lock | FLUSH TABLES WITH READ LOCK 正在等待全局讀鎖或正在設(shè)置全局 read_only 系統(tǒng)變量。 |
Waiting for tables | 線程收到一個通知,表示表的基礎(chǔ)結(jié)構(gòu)已更改,需要重新打開表以獲取新結(jié)構(gòu)。但是,要重新打開表,它必須等到所有其他線程都關(guān)閉了有問題的表。 如果另一個線程在相關(guān)表上使用了 FLUSH TABLES 或以下語句之一,則會發(fā)生此通知: FLUSH TABLES tbl_name 、 ALTER TABLE 、 RENAME TABLE 、 REPAIR TABLE 、 ANALYZE TABLE 或 OPTIMIZE TABLE 。 |
Waiting for table flush | 線程正在執(zhí)行 FLUSH TABLES 并等待所有線程關(guān)閉其表,或者線程收到通知,表示表的底層結(jié)構(gòu)已更改,需要重新打開表以獲取新結(jié)構(gòu)。但是,要重新打開表,它必須等到所有其他線程都關(guān)閉了有問題的表。 如果另一個線程在相關(guān)表上使用了 FLUSH TABLES 或以下語句之一,則會發(fā)生此通知: FLUSH TABLES tbl_name 、 ALTER TABLE 、 RENAME TABLE 、 REPAIR TABLE 、 ANALYZE TABLE 或 OPTIMIZE TABLE 。 |
Waiting for lock_type lock | 服務(wù)器正在等待獲取 THR_LOCK 鎖或來自元數(shù)據(jù)鎖子系統(tǒng)的鎖,其中 lock_type 指示鎖的類型。 此狀態(tài)表示等待 THR_LOCK :Waiting for table level lock 這些狀態(tài)表示等待元數(shù)據(jù)鎖定: Waiting for event metadata lock Waiting for global read lock Waiting for schema metadata lock Waiting for stored function metadata lock Waiting for stored procedure metadata lock Waiting for table metadata lock Waiting for trigger metadata lock 有關(guān)表鎖定指示器的信息,請參見第8.11.1節(jié)“內(nèi)部鎖定方法”。有關(guān)元數(shù)據(jù)鎖定的信息,請參見第8.11.4節(jié)“元數(shù)據(jù)鎖定”。若要查看哪些鎖正在阻塞鎖請求,請使用第25.12.12節(jié)“性能架構(gòu)鎖表”中描述的性能架構(gòu)鎖表。 |
Waiting on cond | 一種泛型狀態(tài),在這種狀態(tài)下,線程正在等待條件變?yōu)檎?。沒有可用的特定狀態(tài)信息。 |
Writing to net | 服務(wù)器正在向網(wǎng)絡(luò)寫入數(shù)據(jù)包。從MySQL 5.7.8開始,這個狀態(tài)被稱為 Sending to client 。 |
1、Sleep
連接資源未釋放,如果是通過連接池連接,sleep狀態(tài)應(yīng)該保持在一定數(shù)據(jù)范圍內(nèi)。
2、Copy to tmp table
索引及現(xiàn)有結(jié)構(gòu)無法涵蓋查詢條件時,會建立一個臨時表來滿足查詢要求,產(chǎn)生巨大的i/o壓力Copy to tmp table通常與連表查詢有關(guān),建議減少關(guān)聯(lián)查詢或者深入優(yōu)化查詢語句,如果出現(xiàn)此狀態(tài)的語句執(zhí)行時間過長,會嚴(yán)重影響其他操作,此時可以kill掉該操作。
3、Sending data
Sending data并不是發(fā)送數(shù)據(jù),是從物理磁盤獲取數(shù)據(jù)的進(jìn)程,如果影響結(jié)果集較多,那么就需要從不同的磁盤碎片去抽取數(shù)據(jù),如果sending data連接過多,通常是某查詢的影響結(jié)果集過大,也就是查詢的索引項(xiàng)不夠優(yōu)化
4、Storing result to query cache
如果頻繁出現(xiàn)此狀態(tài),使用set profiling分析,如果存在資源開銷在SQL整體開銷的比例過大,則說明query cache碎片較多,使用flush query cache可即時清理,Query cache參數(shù)可適當(dāng)酌情設(shè)置
MySQL數(shù)據(jù)庫是常見的兩個瓶頸是CPU和I/O的瓶頸,CPU在飽和的時候一般發(fā)生在數(shù)據(jù)裝入內(nèi)存或從磁盤上讀取數(shù)據(jù)時候。磁盤I/O瓶頸發(fā)生在裝入數(shù)據(jù)遠(yuǎn)大于內(nèi)存容量的時候,如果應(yīng)用分布在網(wǎng)絡(luò)上,那么查詢量相當(dāng)大的時候那么平瓶頸就會出現(xiàn)在網(wǎng)絡(luò)上,可以用mpstat, iostat, sar和vmstat來查看系統(tǒng)的性能狀態(tài)。
除了服務(wù)器硬件的性能瓶頸,對于MySQL系統(tǒng)本身,我們可以使用工具來優(yōu)化數(shù)據(jù)庫的性能,通常有三種:使用索引,使用EXPLAIN分析查詢以及調(diào)整MySQL的內(nèi)部配置。
在優(yōu)化MySQL時,通常需要對數(shù)據(jù)庫進(jìn)行分析,常見的分析手段有慢查詢?nèi)罩?,EXPLAIN 分析查詢,profiling分析以及show命令查詢系統(tǒng)狀態(tài)及系統(tǒng)變量,通過定位分析性能的瓶頸,才能更好的優(yōu)化數(shù)據(jù)庫系統(tǒng)的性能。
MySQL中Varchar(20)和varchar(200)區(qū)別是什么?
數(shù)據(jù)準(zhǔn)備:
CREATE TABLE `user_info_varchar20` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `name` varchar(20) NOT NULL COMMENT '用戶名', `age` tinyint(4) NOT NULL DEFAULT 0 COMMENT '年齡', `sex` tinyint(2) NOT NULL DEFAULT 0 COMMENT '性別 0:男 1: 女', `create_time` datetime NOT NULL DEFAULT NOW() COMMENT '創(chuàng)建時間', `udpate_time` datetime NOT NULL DEFAULT NOW() COMMENT '更新時間', PRIMARY KEY (`id`), KEY `idx_name` (`name`) COMMENT 'name索引' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶賬戶'; CREATE TABLE `user_info_varchar200` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID', `name` varchar(200) NOT NULL COMMENT '用戶名', `age` tinyint(4) NOT NULL DEFAULT 0 COMMENT '年齡', `sex` tinyint(2) NOT NULL DEFAULT 0 COMMENT '性別 0:男 1: 女', `create_time` datetime NOT NULL DEFAULT NOW() COMMENT '創(chuàng)建時間', `udpate_time` datetime NOT NULL DEFAULT NOW() COMMENT '更新時間', PRIMARY KEY (`id`), KEY `idx_name` (`name`) COMMENT 'name索引' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶賬戶';
每張表插入100w數(shù)據(jù):
CREATE DEFINER=`root`@`localhost` PROCEDURE `insertTestData2`(IN total INT) BEGIN DECLARE i INT DEFAULT 1; DECLARE batch_size INT DEFAULT 500; DECLARE var_offset INT DEFAULT 1; DECLARE var_limit INT; DECLARE var_batch_values TEXT; DECLARE var_age TINYINT; #DECLARE var_sex TINYINT; WHILE i < total+1 DO SET var_limit=LEAST(var_offset+batch_size, total+1); SET var_batch_values=''; WHILE i < var_limit DO set var_age=FLOOR(RAND() * (100 - 18) + 18); #set var_sex=IF(RAND() < 0.5, 0, 1); IF i = (var_limit-1) THEN #SET var_batch_values = CONCAT(var_batch_values, CONCAT('(\'', CONCAT('測試用戶', i), '\', ', var_age, ', ', var_sex ,', NOW(), NOW())')); SET var_batch_values = CONCAT(var_batch_values, CONCAT('(\'', CONCAT('測試用戶', i), '\', ', var_age,', 0, NOW(), NOW())')); ELSE #SET var_batch_values = CONCAT(var_batch_values, CONCAT('(\'', CONCAT('測試用戶', i), '\', ', var_age, ', ', var_sex ,', NOW(), NOW()),')); SET var_batch_values = CONCAT(var_batch_values, CONCAT('(\'', CONCAT('測試用戶', i), '\', ', var_age,', 0, NOW(), NOW()),')); END IF; SET i=i+1; END WHILE; SET @sql = CONCAT('INSERT INTO user_info_varchar20(name, age, sex, create_time, udpate_time) VALUES ', var_batch_values); PREPARE stmt FROM @sql; EXECUTE stmt; SET @sql = CONCAT('INSERT INTO user_info_varchar200(name, age, sex, create_time, udpate_time) VALUES ', var_batch_values); PREPARE stmt FROM @sql; EXECUTE stmt; SET var_offset=var_limit; END WHILE; END
存儲空間對比:
SELECT table_schema AS "數(shù)據(jù)庫", table_name AS "表名", table_rows AS "記錄數(shù)", TRUNCATE ( data_length / 1024 / 1024, 4) AS "數(shù)據(jù)容量(MB)", TRUNCATE ( index_length / 1024 / 1024, 4) AS "索引容量(MB)" FROM information_schema.TABLES WHERE table_schema = 'custom_db' and (TABLE_NAME = 'user_info_varchar20' or TABLE_NAME = 'user_info_varchar200') ORDER BY data_length DESC, index_length DESC;
從MySQL統(tǒng)計(jì)表里面看二者差不多(統(tǒng)計(jì)的是個大概值),或者“ANALYZE TABLE tableName”更新統(tǒng)計(jì)信息也可以通過對比IBD文件(里面包含索引數(shù)據(jù)以及表的行數(shù)據(jù))。
方式1:ANALYZE TABLE tableName
ANALYZE TABLE user_info_varchar20; ANALYZE TABLE user_info_varchar200; SELECT table_schema AS "數(shù)據(jù)庫", table_name AS "表名", table_rows AS "記錄數(shù)", TRUNCATE ( data_length / 1024 / 1024, 4) AS "數(shù)據(jù)容量(MB)", TRUNCATE ( index_length / 1024 / 1024, 4) AS "索引容量(MB)" FROM information_schema.TABLES WHERE table_schema = 'custom_db' and (TABLE_NAME = 'user_info_varchar20' or TABLE_NAME = 'user_info_varchar200') ORDER BY data_length DESC, index_length DESC;
方式2: 對比IBD文件
查詢性能對比
測試前開啟MySQL的profiles
show variables like '%profiling%';
set profiling = 1; 開啟
執(zhí)行測試SQL
-- 條件為索引字段查詢 select * from user_info_varchar20 where name = '測試用戶800000'; select * from user_info_varchar200 where name = '測試用戶800000'; -- 排序字段為索引同時搜索字段為索引覆蓋(深分頁) select name from user_info_varchar20 order by name LIMIT 999995, 5; select name from user_info_varchar200 order by name LIMIT 999995, 5; -- 排序字段為索引同時搜索字段為普通字段(深分頁) select * from user_info_varchar20 order by name LIMIT 999995, 5; select * from user_info_varchar200 order by name LIMIT 999995, 5;
執(zhí)行命令show profiles,查看查詢執(zhí)行效率
通過對比發(fā)現(xiàn)varchar(20)和varcha(200)基本差不多,但是在“排序字段為索引同時搜索字段為普通字段(深分頁)”這種情況二者時間差距很大。
-- 索引排序同時深分頁 select * from user_info_varchar20 order by name LIMIT 999995, 5; select * from user_info_varchar200 order by name LIMIT 999995, 5;
show profile 命令繼續(xù)分析
翻看最上面state字段值說明,可知,二者在處理select查詢字段時情況不一樣,但為什么差距這么大呢?
二者不出意外的話應(yīng)該都使用了filesort排序,查詢執(zhí)行計(jì)劃
二者都是查詢字段未完全包含在排序字段中,所以是Using filesort,這個好理解,但是執(zhí)行時間為啥會差距這么大呢?
開啟優(yōu)化分析器,繼續(xù)分析,命令如下:
/* 打開optimizer_trace,只對本線程有效 */ SET optimizer_trace='enabled=on'; /* @a保存Innodb_rows_read的初始值 */ select VARIABLE_VALUE into @a from performance_schema.session_status where variable_name = 'Innodb_rows_read'; /* 執(zhí)行語句 */ select name,age from user_info_varchar200 order by name LIMIT 999995, 5; /* 查看 OPTIMIZER_TRACE 輸出 */ SELECT * from information_schema.OPTIMIZER_TRACE; /* @a保存Innodb_rows_read的初始值 */ select VARIABLE_VALUE into @b from performance_schema.session_status where variable_name = 'Innodb_rows_read'; /* 計(jì)算Innodb_rows_read差值 */ SELECT @b-@a;
表<user_info_varchar20>執(zhí)行結(jié)果:
表<user_info_varchar200>執(zhí)行結(jié)果:
經(jīng)過對比:
二者的排序緩沖區(qū)(sort_buffer_size)大小為1048560(1M),在進(jìn)行歸并排序時,varchar20表用了75個臨時表,而varchar200用到了419個臨時表,臨時文件【恰當(dāng)叫法應(yīng)該是數(shù)據(jù)塊,因?yàn)榈讓又粫蓛蓚€臨時文件chunk和數(shù)據(jù)塊文件】越多(IO次數(shù)就越多),歸并排序性能越差。
所以原因找到了?。。。?span>間接說明varchar(20)與varchar(200)在排序緩沖區(qū)占用內(nèi)存大小不一樣,換種說法就是搜索引擎為兩種長度在緩沖區(qū)分配的內(nèi)存不一樣,再細(xì)節(jié)的原因需要了解MySQL底層fileSort,順便提一句是fileSort的sortKey字節(jié)長度不一樣引起的)。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring jdbc中數(shù)據(jù)庫操作對象化模型的實(shí)例詳解
這篇文章主要介紹了Spring jdbc中數(shù)據(jù)庫操作對象化模型的實(shí)例詳解的相關(guān)資料,希望通過本文大家能夠了解掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09Mysql8.0壓縮包安裝方法(詳細(xì)教程一步步安裝)
這篇文章主要給大家介紹了關(guān)于Mysql8.0壓縮包安裝方法,文中介紹的非常詳細(xì),Mysql安裝的時候可以有msi安裝和zip解壓縮兩種安裝方式,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-07-07Win10下免安裝版MySQL8.0.16的安裝和配置教程圖解
這篇文章主要介紹了Win10下免安裝版MySQL8.0.16的安裝和配置 ,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考解決價值,需要的朋友可以參考下2019-06-06