欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MySQL中一條查詢SQL語句的完整執(zhí)行流程

 更新時(shí)間:2024年05月08日 08:51:56   作者:隨機(jī)的未知  
通常我們?cè)谑褂肕ySQL時(shí),我們看到的只是輸入一條語句,返回一個(gè)結(jié)果,卻不知道這條語句在MySQL內(nèi)部的執(zhí)行過程,這篇文章主要給大家介紹了關(guān)于MySQL中一條查詢SQL語句的完整執(zhí)行流程,需要的朋友可以參考下

表結(jié)構(gòu)和數(shù)據(jù)如下:

我們分析的sql語句如下:

select tb_id,tb_name,tb_address from tb_user where tb_id = 66;

大體來說,MySQL可以分為Server層和存儲(chǔ)引擎層兩部分:

Server層

  • 包括:連接器、查詢緩存、分析器、優(yōu)化器、執(zhí)行器等

  • 涵蓋MySQL的大多數(shù)核心服務(wù)功能

  • 所有的內(nèi)置函數(shù)(如日期、時(shí)間、數(shù)學(xué)和加密函數(shù)等),所有跨存儲(chǔ)引擎的功能都在這一層實(shí)現(xiàn)

    • 比如:存儲(chǔ)過程、觸發(fā)器、視圖等
  • 存儲(chǔ)引擎層:

    • 負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)和提取
    • 可插拔式存儲(chǔ)引擎:InnoDB、MyISAM、Memory等
      • 最常用存儲(chǔ)引擎是InhoDB
      • 從MySQL 5.5版本開始,默認(rèn)存儲(chǔ)引擎是lnnoDB

第一步:連接到數(shù)據(jù)庫

首先會(huì)連接到這個(gè)數(shù)據(jù)庫上,這時(shí)候接待我們的就是連接器。

mysql -uroot -p

連接完成后,如果沒有后續(xù)的動(dòng)作,這個(gè)連接就處于空閑狀態(tài)??蛻舳巳绻L時(shí)間沒動(dòng)靜,連接器就會(huì)自動(dòng)將它斷開。這個(gè)時(shí)間是由參數(shù)wait_timeout控制的,默認(rèn)值是8小時(shí)。

show processlist;

其中的 Command 列顯示為“Sleep”的這一行,就表示現(xiàn)在系統(tǒng)里面有一個(gè)空閑連接。

第二步:查緩存

MySQL拿到一個(gè)查詢請(qǐng)求后,會(huì)先到查詢緩存看看,之前是不是執(zhí)行過這條語句。之前執(zhí)行過的語句及其結(jié)果可能會(huì)以key-value對(duì)的形式,被直接緩存在內(nèi)存中。key是查詢的語句hash之后的值,value是查詢的結(jié)果。

  • 如果查詢語句在緩存中,會(huì)被直接返回給客戶端。

  • 如果語句不在查詢緩存中,就會(huì)繼續(xù)后面的執(zhí)行階段。執(zhí)行完成后,執(zhí)行結(jié)果會(huì)被存入查詢緩存中。

如果查詢命中緩存,MySQL不需要執(zhí)行后面的復(fù)雜操作就可以直接返回結(jié)果,效率會(huì)很高!但是不建議使用MySQL的內(nèi)置緩存功能。

查詢緩存

查詢緩存默認(rèn)是關(guān)閉的狀態(tài)。

# 查看是否開啟緩存
show variables like 'query_cache_type';
# 查看緩存的命中次數(shù):
show status like 'qcache_hits';

開啟緩存

/etc/my.cnf文件中修改“query_cache_type”參數(shù)

值為`0或OFF`會(huì)禁止使用緩存。
值為`1或ON`將啟用緩存,但以`SELECT SQL_NO_CACHE`開頭的語句除外。
值為`2或DEMAND`時(shí),只緩存以`SELECT SQL_CACHE`開頭的語句。

清空查詢緩存

可以使用下面三個(gè)SQL來清理查詢緩存:

# 清理查詢緩存內(nèi)存碎片。
FLUSH QUERY CACHE; 
# 從查詢緩存中移出所有查詢。
RESET QUERY CACHE;
# 關(guān)閉所有打開的表,同時(shí)該操作將會(huì)清空查詢緩存中的內(nèi)容。
FLUSH TABLES; 

不建議使用MySQL的查詢緩存

因?yàn)椴樵兙彺嫱状笥诶?/p>

  • 成本高:查詢緩存的失效非常頻繁,只要有對(duì)一個(gè)表的更新,這個(gè)表上所有的查詢緩存都會(huì)被清空。因此很可能你費(fèi)勁地把結(jié)果存起來,還沒使用呢,就被一個(gè)更新全清空了。

  • 命中率不高:對(duì)于更新壓力大的數(shù)據(jù)庫來說,查詢緩存的命中率會(huì)非常低。除非你的業(yè)務(wù)就是有一張靜態(tài)表,很長時(shí)間才會(huì)更新一次。比如,一個(gè)系統(tǒng)配置表,那這張表上的查詢才適合使用查詢緩存。

  • 功能并不如專業(yè)的緩存工具更好:redis、memcache、ehcache…
    MySQL提供了按需使用的方式,我們可以將參數(shù)query_cache_type設(shè)置成DEMAND,這樣對(duì)于默認(rèn)的SQL語句都不使用查詢緩存。而對(duì)于你確定要使用查詢緩存的語句,可以用SQL_CACHE顯式指定,像下面這個(gè)語句一樣:

    select sql_cache * from tb_user where tb_id = 16;
    

MySQL 8.0 版本直接將查詢緩存的整塊功能刪掉了。

第三步:分析SQL語句

如果查詢緩存沒有命中,接下來就需要進(jìn)入正式的查詢階段了。客戶端程序發(fā)送過來的請(qǐng)求,實(shí)際上只是一個(gè)字符串而已,所以MySQL服務(wù)器程序首先需要對(duì)這個(gè)字符串做分析,判斷請(qǐng)求的語法是否正確,然后從字符串中將要查詢的表、列和各種查詢條件都提取出來,本質(zhì)上是對(duì)一個(gè)SQL語句編譯的過程,涉及詞法解析、語法分析、預(yù)處理器等。

  • 詞法分析:詞法分析就是把一個(gè)完整的SQL語句分割成一個(gè)個(gè)的字符串;
  • 語法分析:語法分析器根據(jù)詞法分析的結(jié)果做語法檢查,判斷你輸入的SQL語句是否滿足MySQL語法;
  • 預(yù)處理器:預(yù)處理器則會(huì)進(jìn)一步去檢查解析樹是否合法,比如表名是否存在,語句中表的列是否存在等等,在這一步MySQL會(huì)檢驗(yàn)用戶是否有表的操作權(quán)限。

詞法分析

比如我們前文所提到的sql語句,分割前為:

select tb_id,tb_name,tb_address from tb_user where tb_id = 66;

分割后為

select,
tb_id,
tb_name,
tb_address,
from,
tb_user,
where,
tb_id,
=,
66
;

MySQL同時(shí)需要識(shí)別出這個(gè)SQL語句的字符串分別是什么,代表什么。

  • 把select關(guān)鍵字識(shí)別出來,是查詢語句;
  • 把tb_user識(shí)別出來是表名tb_user;

語法分析

如果語法正確就會(huì)根據(jù)MySQL語法規(guī)則與SQL語句生成一個(gè)數(shù)據(jù)結(jié)構(gòu)——解析樹;

如果我們把from寫成form

會(huì)報(bào)出如下錯(cuò)誤:

我們前面的SQL語句,生成解析樹如下:

select tb_id,tb_name,tb_address from tb_user where tb_id = 66;

預(yù)處理器

預(yù)處理器會(huì)進(jìn)一步去檢查解析樹是否合法,比如表名是否存在,語句中表的列是否存在等等,在這一步MySQL會(huì)檢驗(yàn)用戶是否有表的操作權(quán)限。

預(yù)處理之后會(huì)得到一個(gè)新的解析樹,然后調(diào)用對(duì)應(yīng)執(zhí)行模塊。

第四步:優(yōu)化SQL語句

優(yōu)化器顧名思義就是對(duì)查詢進(jìn)行優(yōu)化。作用是根據(jù)解析樹生成不同的執(zhí)行計(jì)劃,然后選擇最優(yōu)的執(zhí)行計(jì)劃。

MySQL里面使用的是基于成本模型的優(yōu)化器,哪種執(zhí)行計(jì)劃Explain執(zhí)行時(shí)成本最小就用哪種。而且它是io_cost和cpu_cost的開銷總和,它通常也是我們?cè)u(píng)價(jià)一個(gè)查詢的執(zhí)行效率的一個(gè)常用指標(biāo)。

show status like 'Last_query_cost';

查看上次查詢成本開銷,默認(rèn)值是0

優(yōu)化器可以做的優(yōu)化有:

  • 當(dāng)有多個(gè)索引可用的時(shí)候,決定使用哪個(gè)索引;
  • 在一個(gè)語句有多表關(guān)聯(lián)(join)的時(shí)候,決定各個(gè)表的連接順序,以哪個(gè)表為基準(zhǔn)表。

優(yōu)化器最多是輔助,作用很有限,我們的SQL語句不能依賴于MySQL的優(yōu)化器去調(diào)優(yōu)!

第五步:執(zhí)行SQL語句

判斷執(zhí)行權(quán)限

開始執(zhí)行的時(shí)候,要先判斷一下對(duì)這表tb_user有沒有執(zhí)行查詢的權(quán)限,如果沒有權(quán)限,就會(huì)返回?zé)o權(quán)限的錯(cuò)誤。

比如:我們新建一個(gè)用戶hello_user,只有庫sjdwz_testtab_test的查詢權(quán)限,沒有表tb_user的查詢權(quán)限。

CREATE USER `hello_user`@`localhost` IDENTIFIED BY '7654321@Hello';
GRANT Select ON TABLE `sjdwz_test`.`tab_test` TO `hello_user`@`localhost`;

使用這個(gè)用戶hello_user連接mysql,

mysql -uhello_user -p

執(zhí)行下面的查詢語句,就會(huì)返回沒有權(quán)限的錯(cuò)誤

select tb_id,tb_name,tb_address from tb_user where tb_id = 66;

調(diào)用存儲(chǔ)引擎接口查詢

如果有權(quán)限,就使用指定的存儲(chǔ)引擎打開表開始查詢。執(zhí)行器會(huì)根據(jù)表的引擎定義,去使用這個(gè)引擎提供的查詢接口提取數(shù)據(jù)。

  • tb_id是主鍵執(zhí)行流程:
    • 調(diào)用InnoDB引擎接口,從主鍵索引中檢索c_id=14的記錄。
    • 主鍵索引等值查詢只會(huì)查詢出一條記錄,直接將該記錄返回客戶端。
    • 至此,這個(gè)語句就執(zhí)行完成了。
  • tb_id不是主鍵執(zhí)行流程:全表掃描
    • 調(diào)用InnoDB引擎接口取這個(gè)表的第一行,判斷tb_id 值是不是66,如果不是則跳過,如果是則將這行緩存在結(jié)果集中;
    • 調(diào)用引擎接口取”下一行",重復(fù)相同的判斷邏輯,直到取到這個(gè)表的最后一行。
    • 執(zhí)行器將上述遍歷過程中所有滿足條件的行組成的結(jié)果集返回給客戶端。
    • 至此,這個(gè)語句就執(zhí)行完成了。

總結(jié) 

到此這篇關(guān)于MySQL中一條查詢SQL語句的完整執(zhí)行流程的文章就介紹到這了,更多相關(guān)MySQL一條查詢SQL語句內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論