MySQL慢查詢那點(diǎn)事

----這個(gè)世界需要更多充滿激情的瘋子。


(一)MySQL查詢對(duì)資源的消耗

? ? ? ? ? ? ? ? ? ? 為什么會(huì)慢?

? ? 先從磁盤的IO開(kāi)始分析,首先機(jī)械式磁盤,每次搜尋數(shù)據(jù)的時(shí)候都需要尋道,然后讀取數(shù)據(jù),根據(jù)比較可以看出內(nèi)存的速度是硬盤的10萬(wàn)倍!

我們要把數(shù)據(jù)從硬盤讀取到內(nèi)存的過(guò)程就需要進(jìn)行IO操作,這個(gè)過(guò)程單次IO可能需要耗費(fèi)近10ms的時(shí)間能完成讀取,同時(shí)操作系統(tǒng)又是以塊來(lái)區(qū)分,所以可以認(rèn)為一次IO操作從硬盤讀取n塊數(shù)據(jù)。通過(guò)分析可以知道只要IO操作越少,速度就越快!。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? 那么怎么減少IO操作呢?

? 接下來(lái)看看數(shù)據(jù)庫(kù)中的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)一般是B+樹(shù),B+樹(shù)的特點(diǎn)是所有的數(shù)據(jù)都是存放在葉子節(jié)點(diǎn),同時(shí)是按照順序進(jìn)行存放的!下面是B+樹(shù)的結(jié)構(gòu)


比如我們要找數(shù)據(jù)4,那么首先磁盤第一次IO是定位到P1,通過(guò)二分查找到下一塊的地址P3.這時(shí)候2次的IO讀取到了數(shù)據(jù)項(xiàng)4,可以看出讀取數(shù)據(jù)IO的次數(shù)就是B+樹(shù)的高度!

假設(shè)當(dāng)前數(shù)據(jù)表的數(shù)據(jù)為N,每個(gè)磁盤塊的數(shù)據(jù)項(xiàng)的數(shù)量是m,則有h=㏒(m+1)N,當(dāng)數(shù)據(jù)量N一定的情況下,m越大,h越?。欢鴐 = 磁盤塊的大小 / 數(shù)據(jù)項(xiàng)的大小,磁盤塊的大小也就是一個(gè)數(shù)據(jù)頁(yè)的大小,是固定的,如果數(shù)據(jù)項(xiàng)占的空間越小,數(shù)據(jù)項(xiàng)的數(shù)量越多,樹(shù)的高度越低。

是否豁然開(kāi)朗!這就是為什么每個(gè)數(shù)據(jù)項(xiàng),即索引字段要盡量的小,比如int占4字節(jié),要比bigint8字節(jié)少一半。主要是為了減少樹(shù)的高度!合適的字段類型和大小會(huì)對(duì)效率和速度產(chǎn)生一定的影響!

? ? ? ? ? ? ? ? ? ? ? ? ? 總結(jié)

一定要選擇合適的類型和大小來(lái)約束字段,可以降低B+樹(shù)的高度,從而減少IO次數(shù)。

同時(shí)建立索引的也是一種B+樹(shù)結(jié)構(gòu),通過(guò)索引來(lái)查找數(shù)據(jù)可以更少次數(shù)的IO實(shí)現(xiàn)數(shù)據(jù)的定位。

所以慢查詢的優(yōu)化就是減少IO操作,那么接下來(lái)我們通過(guò)慢查詢?nèi)罩緛?lái)分析如何優(yōu)化!



(二)MySQL日志類型

首先我們來(lái)看看MySQL的日志構(gòu)成:

? ? MySQL日志文件系統(tǒng)的組成

? ? a、錯(cuò)誤日志:記錄啟動(dòng)、運(yùn)行或停止mysqld時(shí)出現(xiàn)的問(wèn)題。

? ? b、通用日志:記錄建立的客戶端連接和執(zhí)行的語(yǔ)句。

? ? c、更新日志:記錄更改數(shù)據(jù)的語(yǔ)句。該日志在MySQL 5.1中已不再使用。

? ? d、二進(jìn)制日志:記錄所有更改數(shù)據(jù)的語(yǔ)句。還用于復(fù)制。

e、慢查詢?nèi)罩?/b>:記錄所有執(zhí)行時(shí)間超過(guò)long_query_time秒的所有查詢或不使用索引的查詢。

? ? f、Innodb日志:innodb redo log

? ? 好了我們捕獲到了我們需要的東西,那就是慢查詢?nèi)罩?!我們?lái)看看一般的慢查尋日志是否有在MySQL中開(kāi)啟:

在命令行模式下執(zhí)行:show variables like 'slow%';

slow_query_log:OFF表示沒(méi)有開(kāi)啟慢查詢,需要先開(kāi)啟來(lái)哦~

有了慢查詢?nèi)罩窘酉聛?lái)就是我們要針對(duì)性的對(duì)消耗時(shí)間超過(guò)設(shè)定的sql語(yǔ)句進(jìn)行針對(duì)性的優(yōu)化,

到了這一步我們就可以知道到底什么語(yǔ)句影響了數(shù)據(jù)庫(kù)的查詢性能!



(三)MySQL語(yǔ)句分析

有了日志,我們才能快速定位問(wèn)題。首先我們來(lái)看看系統(tǒng)給出的一個(gè)慢查詢?nèi)罩?/b>

# Time: 180112 16:50:45

# User@Host: a8591[a8591] @? [192.168.1.132]

# Thread_id: 26880039011? Schema: a8591? Last_errno: 0? Killed: 0

# Query_time: 1.336462? Lock_time: 0.000089? Rows_sent: 0? Rows_examined: 3499535? Rows_affected: 0? Rows_read: 0

# Bytes_sent: 733? Tmp_tables: 0? Tmp_disk_tables: 0? Tmp_table_sizes: 0

SET timestamp=1515747045;

SELECT * FROM `serviceRecord` WHERE ( `tag` = 120 ) AND ( `theId` = 2741372 ) LIMIT 1;

我們來(lái)解析一下日志各個(gè)參數(shù)的含義:

Query_time:1.336462? ? ? ? ? ? ? ? ? ? ? 查詢消耗的時(shí)間

Lock_time:0.000089? ? ? ? ? ? ? ? ? ? ? ? 鎖表時(shí)間

Rows_sent: 0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 發(fā)送或返回的行數(shù)

Rows_examined:3499535? ? ? ? ? ? ? ? 查詢行數(shù)? ?

解決方法:

1.先 執(zhí)行DESC SELECT * FROM `serviceRecord` WHERE ( `tag` = 120 ) AND ( `theId` = 2741372 ) LIMIT 1;進(jìn)行分析


這里的字段解析:

主要是看key是否用到了索引,這里我們發(fā)現(xiàn)key是NULL,所以這條語(yǔ)句沒(méi)有經(jīng)過(guò)任何索引.

然后分析慢日志:

這條是非常簡(jiǎn)單的查詢語(yǔ)句,但是卻查了300多萬(wàn)行的數(shù)據(jù),非常明顯沒(méi)有通過(guò)索引,查看數(shù)據(jù)庫(kù)的表結(jié)構(gòu)

分析一下,索引有兩個(gè),一個(gè)是id的主鍵索引,一個(gè)是(type,theId,recTime)的聯(lián)合索引。

我們的查詢語(yǔ)句:SELECT * FROM `serviceRecord` WHERE ( `tag` = 120 ) AND ( `theId` = 2741372 ) LIMIT 1;

很明顯沒(méi)有走任何索引導(dǎo)致了全表掃描!

根據(jù)業(yè)務(wù)是關(guān)于一些消息記錄的,theId是非常常用的一個(gè)字段,區(qū)分度也非常高,因此我們需要對(duì)theId進(jìn)行索引的建立,而tag標(biāo)簽的區(qū)分度并不算高,所以暫時(shí)沒(méi)有必要進(jìn)行索引的建立。


參考:http://blog.csdn.net/gent__chen/article/details/51159451

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容