簡(jiǎn)介
參考文獻(xiàn):03丨學(xué)會(huì)用數(shù)據(jù)庫的方式思考SQL是如何執(zhí)行的
以oracle和MySQL為例,講解了sql是怎么被執(zhí)行的,并且對(duì)比了執(zhí)行過程中,oracle和MySQL的異同。
個(gè)人感覺,講解的核心是SQL執(zhí)行時(shí)的緩存機(jī)制。
Oracle中的sql是如何執(zhí)行的
自我口述一下
sql語句在提交后,
首先進(jìn)行“語法檢查”,檢查sql語法是否正確,關(guān)鍵字等的拼寫是否異常;
然后進(jìn)行“語義檢查”,檢查sql中涉及到的訪問對(duì)象是否存在,比如說from的表,或者是select的字段等。
語法檢查和語義檢查是為了避免sql語句本身出現(xiàn)錯(cuò)誤,保證sql語句是可以運(yùn)行的。
然后進(jìn)行“權(quán)限檢查”,檢查當(dāng)前用戶是否有所調(diào)用表的訪問權(quán)限,是否可以訪問這些數(shù)據(jù)。
然后進(jìn)行“共享池檢查”, 這一步是檢查sql語句及其執(zhí)行計(jì)劃是否緩存在共享池中,如果當(dāng)前有緩存,就將它們?nèi)〕鰜恚@個(gè)過程被稱為sql語句的軟解析;如果該語句和其對(duì)應(yīng)的執(zhí)行計(jì)劃沒有緩存過,那sql語句將被送進(jìn)“優(yōu)化器”,創(chuàng)建解析樹對(duì)其解析,同時(shí)生成執(zhí)行計(jì)劃,這個(gè)過程被稱為硬解析。
在執(zhí)行計(jì)劃就位后,就知道了sql該怎么被執(zhí)行,這時(shí)候再進(jìn)行“執(zhí)行器”階段,執(zhí)行sql語句,返回執(zhí)行結(jié)果。
共享池(shared pool)是oracle中的術(shù)語,是一塊內(nèi)存池,包括了庫緩存區(qū)和數(shù)據(jù)字典緩存區(qū)。庫緩存區(qū)主要是用來緩存sql語句和其執(zhí)行計(jì)劃,數(shù)據(jù)字典緩存區(qū)存儲(chǔ)的是Oracle中各種對(duì)象,如表、視圖、索引等對(duì)象,其緩存細(xì)粒度更小,但也更實(shí)用,當(dāng)對(duì)sql語句進(jìn)行解析的時(shí)候,如果需要相應(yīng)的對(duì)象,那直接去數(shù)據(jù)字典緩存區(qū)去找。
那庫緩存過程中,Oracle是怎么進(jìn)行軟解析的呢?
Oracle首先對(duì)SQL語句做hash運(yùn)算,然后根據(jù)得到的hash值,在庫緩存(library Cache)中查找,找得到就取出來,做軟解析,找不到的話那就只能硬解析。
為了提升sql的執(zhí)行效率,我們應(yīng)該盡量避免硬解析,因?yàn)樵趕ql的執(zhí)行過程中,創(chuàng)建解析樹,生成執(zhí)行計(jì)劃是相當(dāng)耗資源的。
那在Oracle中,如何主動(dòng)避免使用硬解析呢?
Oracle提供了一種方法,就是綁定變量。
Oracle中使用綁定變量來避免一類執(zhí)行計(jì)劃的無謂消耗。
在Oracle中,以下兩個(gè)sql語句是會(huì)生成兩套執(zhí)行計(jì)劃的,即使這兩套執(zhí)行計(jì)劃是一模一樣的:
select * from player where player_id = 1001
select * from player where player_id = 1002
只要后面的常數(shù)變了,那么每一次查詢都會(huì)創(chuàng)建一個(gè)新的查詢解析。這種花銷是不必要的,于是Oracle提出了綁定變量:
select * from player where player_id = :player_id
采用了綁定變量后,在第一次查詢后,共享池中就會(huì)緩存此類查詢的執(zhí)行計(jì)劃,主動(dòng)避免了下次的硬解析。
簡(jiǎn)單百度了下,Oracle中應(yīng)該是大量使用綁定變量來主動(dòng)避免硬解析。但并不是說綁定變量就是萬能的,這種類似動(dòng)態(tài)sql的方式,可能過于固化,優(yōu)化的話也比較難。
當(dāng)然,以上是官方說法,我不是很懂,只是下意識(shí)覺得過于僵硬,不容易變通
MySQL中的sql是如何執(zhí)行的
Mysql的執(zhí)行過程跟Oracle有相同的地方,也有不同的地方。
sql語句送入后,
首先進(jìn)行緩存查詢,如果緩存中有這條sql語句,那就直接把結(jié)果返回給客戶端;如果沒有,則進(jìn)入解析器階段。需要特殊說明的是,這種緩存查詢方式效率不高,在MySQL8.0后就被拋棄了。
至于為什么說它查詢效率不高,原因很簡(jiǎn)單。每次表發(fā)生變動(dòng)后,比如說加入了新數(shù)據(jù),原先依賴這張表的緩存查詢就全部失效被清空,而大部分表實(shí)際上都是在時(shí)刻變動(dòng)的,這種緩存機(jī)制只對(duì)不會(huì)更新的靜態(tài)表有作用,對(duì)實(shí)時(shí)更新的動(dòng)態(tài)表來說,這種緩存機(jī)制的作用反而是負(fù)面的,反而增加了sql的查詢時(shí)間,畢竟每次運(yùn)行完后還要花時(shí)間緩存一下結(jié)果,哪怕下一秒這個(gè)結(jié)果就沒用了。
解析器階段,會(huì)做語法分析和語義分析;
然后是優(yōu)化器階段,確定執(zhí)行計(jì)劃;
然后是執(zhí)行器階段,執(zhí)行前會(huì)先進(jìn)行權(quán)限鑒定,判斷該用戶是否具備查詢權(quán)限。如果具備,則執(zhí)行sql并返回結(jié)果。如果是MySQL8.0以下的版本,如果設(shè)置了查詢緩存,則會(huì)同時(shí)將查詢結(jié)果進(jìn)行緩存。
可以看到,MySQL和Oracle的執(zhí)行流程大體上是相同的,或者說執(zhí)行思路是相同的。
不同的地方主要是MySQL的引擎特性引起的。MySQL作為一種優(yōu)秀的開源數(shù)據(jù)庫,其數(shù)據(jù)引擎采用插件的方式,提供了多種引擎可供選擇,甚至,還允許開發(fā)人員設(shè)置自己的開發(fā)引擎。一些具體的開發(fā)引擎就不介紹了,放個(gè)簡(jiǎn)單的截圖吧。
需要注意的一點(diǎn)是,MySQL中每個(gè)表的設(shè)計(jì)都可以采用不同的數(shù)據(jù)庫引擎,你完全可以根據(jù)表本身的特性,靈活選擇其對(duì)應(yīng)的數(shù)據(jù)庫引擎,這也是MySQL的強(qiáng)大之處。文章來源:http://www.zghlxwxcb.cn/news/detail-488343.html
另一個(gè)需要提的是,如何在sql中查看每一句sql在執(zhí)行時(shí)所使用的資源和時(shí)間等信息。即使用profiling。具體用法就不提了,需要用到的時(shí)候自己查吧。文章來源地址http://www.zghlxwxcb.cn/news/detail-488343.html
到了這里,關(guān)于數(shù)據(jù)庫中的SQL是如何執(zhí)行的?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!