佳木斯湛栽影视文化发展公司

主頁(yè) > 知識(shí)庫(kù) > SQL Server中的執(zhí)行引擎入門 圖解

SQL Server中的執(zhí)行引擎入門 圖解

熱門標(biāo)簽:百度競(jìng)價(jià)排名 網(wǎng)站排名優(yōu)化 AI電銷 地方門戶網(wǎng)站 Linux服務(wù)器 鐵路電話系統(tǒng) 服務(wù)外包 呼叫中心市場(chǎng)需求
本文旨在分類講述執(zhí)行計(jì)劃中每一種操作的相關(guān)信息。

數(shù)據(jù)訪問(wèn)操作

    首先最基本的操作就是訪問(wèn)數(shù)據(jù)。這既可以通過(guò)直接訪問(wèn)表,也可以通過(guò)訪問(wèn)索引來(lái)進(jìn)行。表內(nèi)數(shù)據(jù)的組織方式分為堆(Heap)和B樹,其中表中沒(méi)有建立聚集索引時(shí)數(shù)據(jù)是通過(guò)堆進(jìn)行組織的,這個(gè)是無(wú)序的,表中建立聚集索引后和非聚集索引的數(shù)據(jù)都是以B樹方式進(jìn)行組織,這種方式數(shù)據(jù)是有序存儲(chǔ)的。通常來(lái)說(shuō),非聚集索引僅僅包含整個(gè)表的部分列,對(duì)于過(guò)濾索引,還僅僅包含部分行。

    除去數(shù)據(jù)的組織方式不同外,訪問(wèn)數(shù)據(jù)也分為兩種方式,掃描(Scan)和查找(Seek),掃描是掃描整個(gè)結(jié)構(gòu)的所有數(shù)據(jù),而查找只是查找整個(gè)結(jié)構(gòu)中的部分?jǐn)?shù)據(jù)。因此可以看出,由于堆是無(wú)序的,所以不可能在堆上面進(jìn)行查找(Seek)操作,而相對(duì)于B樹的有序,使得在B樹中進(jìn)行查找成為可能。當(dāng)針對(duì)一個(gè)以堆組織的表進(jìn)行數(shù)據(jù)訪問(wèn)時(shí),就會(huì)進(jìn)行堆掃描,如圖1所示。

   

    圖1.表掃描

    可以看出,表掃描的圖標(biāo)很清晰的表明表掃描的性質(zhì),在一個(gè)無(wú)序組織表中從頭到尾掃描一遍。

    而對(duì)于B樹結(jié)構(gòu)的聚集索引和非聚集索引,同樣可以進(jìn)行掃描,通常來(lái)講,為了獲取索引表中的所有數(shù)據(jù)或是獲得索引行樹占了數(shù)據(jù)大多數(shù)使得掃描的成本小于查找時(shí),會(huì)進(jìn)行聚集索引掃描。如圖2所示。

   

    圖2.聚集索引掃描

    聚集索引掃描的圖標(biāo)也同樣能夠清晰的表明聚集索引掃描的性質(zhì),找到最左邊的葉子節(jié)點(diǎn)后,依次掃描所有葉子節(jié)點(diǎn),達(dá)到掃描整個(gè)結(jié)構(gòu)的作用。當(dāng)然對(duì)于非聚集索引也是同樣的概念,如圖3所示。

   

    圖3.非聚集索引的掃描

    而對(duì)于僅僅選擇B樹結(jié)構(gòu)中的部分?jǐn)?shù)據(jù),索引查找(Seek)使得B樹變得有意義。根據(jù)所查找的關(guān)鍵值,可以使得從僅僅從B樹根部向下走單一路徑,因此免去了掃描不必要頁(yè)的消耗,圖4是查詢計(jì)劃中的一個(gè)索引查找。

   

    圖4.聚集索引查找

    索引查找的圖標(biāo)也是很傳神的,可以看到圖標(biāo)那根線從根節(jié)點(diǎn)一路向下到葉子節(jié)點(diǎn)。也就是找到所求數(shù)據(jù)所在的頁(yè),不難看出,如果我們需要查找多條數(shù)據(jù)且分散在不同的頁(yè)中,這個(gè)查找操作需要重復(fù)執(zhí)行很多回,當(dāng)這個(gè)次數(shù)大到一定程度時(shí),SQL Server會(huì)選擇消耗比較低的索引掃描而不是再去重復(fù)索引查找。對(duì)于非聚集索引查找,概念是一樣的,就不再上圖片了。

書簽查找(Bookmark Lookup)

     你也許會(huì)想,假如非聚集索引可以快速的找到所求的數(shù)據(jù),但遺憾的是,非聚集索引卻不包含所有所求列時(shí)該怎么辦?這時(shí)SQL Server會(huì)面臨兩個(gè)選擇,直接訪問(wèn)基本表去獲取數(shù)據(jù)或是在非聚集索引中找到數(shù)據(jù)后,再去基本表獲得非聚集索引沒(méi)有覆蓋到的所求列。這個(gè)選擇取決于所估計(jì)的行數(shù)等統(tǒng)計(jì)信息。查詢分析器會(huì)選擇消耗比較少的那個(gè)。

    一個(gè)簡(jiǎn)單的書簽查找如圖5所示。

   

    圖5.一個(gè)簡(jiǎn)單的書簽查找

    從圖5可以看出,首先通過(guò)非聚集索引找到所求的行,但這個(gè)索引并不包含所有的列,因此還要額外去基本表中找到這些列,因此要進(jìn)行鍵查找,如果基本表是以堆進(jìn)行組織的,那么這個(gè)鍵查找(Key Lookup)就會(huì)變成RID查找(RID Lookup),鍵查找和RID查找統(tǒng)稱為書簽查找。

    不過(guò)有時(shí)候索引查找所返回的行數(shù)過(guò)多導(dǎo)致書簽查找的性能遠(yuǎn)不如直接進(jìn)行掃描操作,因此SQL Server這時(shí)會(huì)選擇掃描而不是書簽查找。如圖6所示。

   

    圖6.StateProvinceID列有非聚集索引,但由于返回行數(shù)過(guò)多,分析器會(huì)選擇掃描而不是書簽查找   

    這個(gè)估計(jì)是根據(jù)統(tǒng)計(jì)信息進(jìn)行的,關(guān)于統(tǒng)計(jì)信息,可以看我之前的一篇博文:淺談SQL Server中統(tǒng)計(jì)對(duì)于查詢的影響

聚合操作(Aggregation)

    聚合函數(shù)會(huì)導(dǎo)致聚合操作。聚合函數(shù)是將一個(gè)集合的數(shù)據(jù)按照某種規(guī)則匯總成1個(gè)數(shù)據(jù),或基于分組按照規(guī)則匯總成多個(gè)數(shù)據(jù)的過(guò)程。一些聚合函數(shù)比如:avg,sum,min,另外還有distinct關(guān)鍵字都有可能導(dǎo)致兩類聚合操作:流聚合(Stream Aggregation)和哈希聚合(Hash Aggregation)。

流聚合(Stream Aggregation)

    流聚合需要再執(zhí)行聚合函數(shù)之前,被聚合的數(shù)據(jù)集合是有序的,這個(gè)有序數(shù)據(jù)既可以通過(guò)執(zhí)行計(jì)劃中的Sort進(jìn)行,也可以直接從聚集或是非聚集索引中直接獲得有序數(shù)據(jù),另外,沒(méi)有Group by的聚合操作被成為標(biāo)量聚合,這類操作一定是會(huì)執(zhí)行流聚合。

    比如,我們直接進(jìn)行標(biāo)量聚合,如圖7所示。

   

    圖7.流聚合

   但對(duì)于加了Group by的子句,因?yàn)樾枰獢?shù)據(jù)按照group by 后面的列有序,就需要Sort來(lái)保證排序。注意,Sort操作是占用內(nèi)存的操作,當(dāng)內(nèi)存不足時(shí)還會(huì)去占用tempdb。SQL Server總是會(huì)在Sort操作和散列匹配中選擇成本最低的。一個(gè)需要Sort的操作如圖8所示。

   

    圖8.需要排序的流聚合

    圖8中排序操作按照ProductLine進(jìn)行排序后,然后就根據(jù)各自的分組做聚合操作了。

散列聚合(Hash aggregation)

    上面的流聚合適合比較少的數(shù)據(jù),但是對(duì)于相對(duì)大一點(diǎn)的表。使用散列集合成本會(huì)比排序要低。散列集合通過(guò)在內(nèi)存中建立散列表來(lái)實(shí)現(xiàn)聚合,因此無(wú)需對(duì)數(shù)據(jù)集合進(jìn)行排序。內(nèi)存中所建立的散列表以Group by后面的列作為鍵值,如圖9所示。

   
    圖9.散列聚合

    在內(nèi)存中建立好散列表后,會(huì)按照group by后面的值作為鍵,然后依次處理集合中的每條數(shù)據(jù),當(dāng)鍵在散列表中不存在時(shí),向散列表添加條目,當(dāng)鍵已經(jīng)在散列表中存在時(shí),按照規(guī)則(規(guī)則是聚合函數(shù),比如Sum,avg什么的)計(jì)算散列表中的值(Value)。

連接(Join)

    當(dāng)多表連接時(shí)(書簽查找,索引之間的連接都算),SQL Server會(huì)采用三類不同的連接方式:循環(huán)嵌套連接(Nested Loops Join),合并連接(Merge Join),散列連接(Hash Join)。這幾種連接并不是哪種會(huì)比另一種更好,而是每種連接方式都會(huì)適應(yīng)特定場(chǎng)景。

循環(huán)嵌套連接(Nested Loops Join)

    由圖10可以看到一個(gè)簡(jiǎn)單的循環(huán)嵌套連接。

   

    圖10.一個(gè)循環(huán)嵌套連接的實(shí)例

    循環(huán)嵌套連接的圖標(biāo)同樣十分傳神,處在上面的外部輸入(Outer input),這里也就是聚集索引掃描。和處在下面的內(nèi)部輸入(Inner Input),這里也就是聚集索引查找。外部輸入僅僅執(zhí)行一次,根據(jù)外部輸入滿足Join條件的每一行,對(duì)內(nèi)部輸入進(jìn)行查找。這里由于是290行,對(duì)于內(nèi)部輸入執(zhí)行290次。

    可以通過(guò)屬性窗口看到.如圖11所示:

   

    圖11.內(nèi)部輸入的執(zhí)行次數(shù)

    根據(jù)嵌套循環(huán)的原理不難看出,由于外部輸入是掃描,內(nèi)部輸入是查找,當(dāng)兩個(gè)Join的表外部輸入結(jié)果集比較小,而內(nèi)部輸入所查找的表非常大時(shí),查詢優(yōu)化器更傾向于選擇循環(huán)嵌套方式。

合并連接(Merge Join)

    不同于循環(huán)嵌套的是,合并連接是從每個(gè)表僅僅執(zhí)行一次訪問(wèn)。從這個(gè)原理來(lái)看,合并連接要比循環(huán)嵌套要快了不少。下面來(lái)看一個(gè)典型的合并連接,如圖12所示。

   

    圖12.合并連接

    從合并連接的原理不難想象,首先合并連接需要雙方有序.并且要求Join的條件為等于號(hào)。因?yàn)閮蓚€(gè)輸入條件已經(jīng)有序,所以從每一個(gè)輸入集合中取一行進(jìn)行比較,相等的返回,不相等的舍棄,從這里也不難看出Merge join為什么只允許Join后面是等于號(hào)。從圖11的圖標(biāo)中我們可以看出這個(gè)原理。

    如果輸入數(shù)據(jù)的雙方無(wú)序,則查詢分析器不會(huì)選擇合并連接,我們也可以通過(guò)索引提示強(qiáng)制使用合并連接,為了達(dá)到這一目的,執(zhí)行計(jì)劃必須加上一個(gè)排序步驟來(lái)實(shí)現(xiàn)有序,如圖13所示。

   

    圖13.通過(guò)排序來(lái)實(shí)現(xiàn)Merge Join

散列連接(Hash Join)

    散列連接同樣僅僅只需要只訪問(wèn)1次雙方的數(shù)據(jù)。散列連接通過(guò)在內(nèi)存中建立散列表實(shí)現(xiàn)。這比較消耗內(nèi)存,如果內(nèi)存不足還會(huì)占用tempdb。但并不像合并連接那樣需要雙方有序。一個(gè)典型的散列連接如圖14所示。

   

    圖14.散列連接

    這里我刪除了Costomer的聚集索引,否則兩個(gè)有序輸入SQL Server會(huì)選擇代價(jià)更低的合并連接。SQL Server利用兩個(gè)上面的輸入生成哈希表,下面的輸入來(lái)探測(cè),可以在屬性窗口看到這些信息,如圖15所示。

   

    圖15.散列鍵生成和散列鍵探測(cè)

 

    通常來(lái)說(shuō),在兩個(gè)輸入數(shù)據(jù)比較大,且所求數(shù)據(jù)在其中一方或雙方?jīng)]有排序的條件達(dá)成時(shí),會(huì)選用散列匹配。

并行

    當(dāng)多個(gè)表連接時(shí),SQL Server還允許在多CPU或多核的情況下允許查詢并行,這樣無(wú)疑提高了效率,一個(gè)并行的例子如圖16所示。

   

   圖16.并行提高效率

總結(jié)

    本文簡(jiǎn)單介紹了SQL Server執(zhí)行計(jì)劃中常見的操作極其原理,了解這些步驟和原理是優(yōu)化查詢的基本功。

您可能感興趣的文章:
  • MySQL 常見存儲(chǔ)引擎的優(yōu)劣
  • 修改MySQL數(shù)據(jù)庫(kù)引擎為InnoDB的操作
  • 關(guān)于MySQL Memory存儲(chǔ)引擎的相關(guān)知識(shí)
  • 詳解mysql中的存儲(chǔ)引擎
  • MySQL 選擇合適的存儲(chǔ)引擎
  • 聊聊MySQL中的存儲(chǔ)引擎
  • MySQL創(chuàng)建數(shù)據(jù)表時(shí)設(shè)定引擎MyISAM/InnoDB操作
  • 簡(jiǎn)述MySQL InnoDB存儲(chǔ)引擎
  • 如何自己動(dòng)手寫SQL執(zhí)行引擎

標(biāo)簽:仙桃 黃山 蘭州 崇左 衡水 湖南 銅川 湘潭

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《SQL Server中的執(zhí)行引擎入門 圖解》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    嘉黎县| 突泉县| 沁阳市| 玛曲县| 巴青县| 绥阳县| 周口市| 泽州县| 璧山县| 阜阳市| 右玉县| 奉化市| 惠东县| 定西市| 抚宁县| 石狮市| 冷水江市| 西安市| 安塞县| 靖远县| 西丰县| 铜川市| 广汉市| 韶关市| 胶州市| 柘荣县| 长治市| 尼勒克县| 资源县| 富裕县| 沁水县| 驻马店市| 明溪县| 吉木萨尔县| 延长县| 伊金霍洛旗| 思南县| 新巴尔虎右旗| 炉霍县| 宝鸡市| 眉山市|