數(shù)據(jù)庫查詢優(yōu)化入門: 代數(shù)與物理優(yōu)化基礎(chǔ)

一. 關(guān)系數(shù)據(jù)庫系統(tǒng)的查詢處理過程

要做優(yōu)化, 首先理解查詢處理過程.
查詢處理: 把用戶提交給RDBMS的查詢語句轉(zhuǎn)換為高效的查詢執(zhí)行計劃.
經(jīng)過的步驟: 查詢分析, 查詢檢查, 查詢優(yōu)化(指的是DBMS完成的)和查詢執(zhí)行.

1)查詢分析

對查詢語句進(jìn)行掃描, 詞法分析(識別出保留字, 變量, 運(yùn)算符, 發(fā)現(xiàn)拼寫錯誤)和語法分析(判斷是否符合SQL的語法規(guī)則, 出現(xiàn)錯誤就報告SQL語法錯誤)

2)查詢檢查

有效性檢查: 對符合語法規(guī)則的查詢語句進(jìn)行語義檢查, 也就是根據(jù)數(shù)據(jù)字典中有關(guān)的模式定義去檢查語句中的數(shù)據(jù)庫對象, 比如表名, 屬性名是否都在存在和有效.
視圖轉(zhuǎn)換: 把對視圖的操作求解, 轉(zhuǎn)換成對基本表的操作
安全性: 還要檢查用戶權(quán)限
完整性檢查: 根據(jù)數(shù)據(jù)字典中存儲的完整性約束進(jìn)行檢查(主鍵約束, 外鍵約束, 用戶自定義約束非空, 取值范圍等).
如果都沒有問題, 那么就把SQL查詢語句轉(zhuǎn)換成內(nèi)部表示(等價的關(guān)系代數(shù)表達(dá)式), 構(gòu)建出一棵查詢的語法分析樹.

語法分析樹

3) 查詢優(yōu)化

是數(shù)據(jù)庫技術(shù)的關(guān)鍵. 劃分為代數(shù)優(yōu)化(邏輯優(yōu)化), 物理優(yōu)化(存取路徑, 底層算法).
優(yōu)化的依據(jù): 基于規(guī)則, 基于代價, 基于語義
優(yōu)化器得出一個執(zhí)行策略, 并生成相應(yīng)的查詢計劃.

4) 查詢執(zhí)行

由code generator負(fù)責(zé)生成執(zhí)行能夠"查詢計劃"的實(shí)際代碼, 然后加以執(zhí)行并回送查詢結(jié)果.
一個典型的查詢過程可以參考這個, 里面寫的非常詳細(xì)!! http://www.jb51.net/article/33535.htm

過程

二. 查詢優(yōu)化

1. 查詢優(yōu)化的意義

把最好的程序員的思維做在了DBMS中, 并且提供數(shù)據(jù)庫存儲的數(shù)據(jù)字典, 物理存儲信息供決策, 比普通應(yīng)用程序員自己寫的好很多. 因此選擇比較好的DBMS, 本身就是查詢優(yōu)化的基礎(chǔ)條件.

2. 選擇操作的算法

naive table scan: 全表掃描, 按照物理次序讀取Student表的M個block到內(nèi)存, 檢查是否滿足條件, 滿足則輸出.
index scan: 如果選擇條件中的屬性上有索引(比如學(xué)號, 姓名, age可能有B+), 那么可以用索引掃描方法, 通過索引先找到滿足條件的元組的指針, 然后通過指針在基本表中找到元組.

3. 連接操作的算法

連接操作在select中是最最最費(fèi)時間的, 因此有很多種算法.
做一個簡單的連接比如select * from student S inner join on SC where S.sno = SC.sno;

  1. naive nested loop join: O(N^2), 嵌套循環(huán)
  2. sort-merge join排序合并算法: 假設(shè)sno做連接, 那么兩個表都按照sno排序, 排好序了以后按照Student, 對SC進(jìn)行掃描, 注意由于排好序了, 因此兩張表都只要掃描一遍即可, 總的時間復(fù)雜度是O(NlgN + 2N) = O(NlgN)
    如果已經(jīng)排好序了, 那就更快了.
  3. index join: 假設(shè)SC表上已經(jīng)建立了屬性sno的索引, 那么對于Student中的每一個元組, 在SC中找到對應(yīng)的元組的時間就不是全表掃描O(N), 而是O(lgN).
  4. hash join: (神奇的hash大法!) 對記錄行數(shù)較少的那張表, 假設(shè)是Student表, 建立一個hashtable, 然后對大表SC, 用同樣的hash函數(shù), 對每個元組上的sno進(jìn)行hash, 如果在hashtable中有對應(yīng)的Student元組, 就連接.
    整個時間開銷是O(N), 當(dāng)然了, 相比其他算法, 額外的空間開銷是O(N).

4. 代價模型

在大數(shù)據(jù)條件下, 代價模型不能只是簡單的CPU時間和內(nèi)存開銷. 要關(guān)注IO和網(wǎng)絡(luò)通信這些比較慢的瓶頸.
DBMS會根據(jù)其特有的代價模型來計算各種查詢執(zhí)行策略的代價, 然后選取代價最小的方案.
對集中式數(shù)據(jù)庫: 主要開銷是IO
對分布式數(shù)據(jù)庫: 主要開銷是IO + 網(wǎng)絡(luò)通信代價

5. 以一個實(shí)例分析連接操作的時間開銷

select Student.sname from Student, SC where Student.sno = SC.sno and SC.cno = 2;

  1. naive: 先全體連接再逐個篩選
    假設(shè)1000行Student記錄, 10000行SC選課記錄, 假設(shè)1個block能放10行Student, 1個block也能放100行SC.
    那么naive算法IO開銷 = (假設(shè)內(nèi)存最多放6個block)
    讀入行記錄: 1000/10 + (10000/100) * ( 1000/(105) ) = 2100 block
    寫入中間結(jié)果到硬盤: 1000
    10000 / 10 = 10^6 block
    讀出中間結(jié)果, 進(jìn)行where條件篩選: 10^6 block
    選擇列, 做輸出: 0
    所以IO開銷 = x * 10^6
    這其實(shí)也是mapreduce為什么這么慢的原因...大量的IO開銷.

  2. 優(yōu)化: 先篩選再連接
    對查詢的優(yōu)化, 應(yīng)當(dāng)關(guān)注如何降低參與連接的元組數(shù)目. 本語句中, 先進(jìn)行where篩選, 再連接才是正道.
    讀入SC所有元組進(jìn)行篩選: 10000/100 = 100 block
    由于篩選出來的元組很少, 比如只有50行 (1個block), 那么放在內(nèi)存中即可, 不用落盤.
    讀入Student所有元組進(jìn)行連接: 1000/10 = 100 block
    連接的時候, 把結(jié)果需要存盤: 100 * 5 = 500 block,
    再對這500個block進(jìn)行連接條件的篩選, 需要讀入: 500 block

100 + 100 + 500*2 = 1200
所以IO開銷 = x * 10^3
降低到了千分之一的數(shù)量級別.

這種先做選擇, 再做連接的基本優(yōu)化, 叫做代數(shù)優(yōu)化. 因?yàn)槲覀儾]有建立或者利用任何物理結(jié)構(gòu), 因此代數(shù)優(yōu)化是算法上的優(yōu)化.
同樣地, 如果我們對SC表中sno建立了B+Tree index, 那么我們就不用讀入所有的塊, 只要讀取包含指定sno的塊,這樣也能提高速度, 這叫做物理優(yōu)化.

三. 代數(shù)優(yōu)化

1. 核心問題

關(guān)系代數(shù)表達(dá)式的等價變換規(guī)則
經(jīng)驗(yàn)性的優(yōu)化策略

2. 變換五大核心規(guī)則

總結(jié)起來就是: "(連接類的)交換律, 結(jié)合律; (投影和選擇類的)串接律, (這兩大類相互之間)分配率"

  1. E1 X E2 = E2 X E1, (E1 X E2) X E3 = E1 X (E2 X E3)做笛卡爾積, 多個表做連接是滿足交換律和結(jié)合律的

  2. 投影和選擇的串接定律
    多層的投影可以取小的那個
    多層的選擇可以取交集(其實(shí)也是那個范圍比較小的), 這樣能夠把多次選擇多次表的掃描, 改成一次.

  3. 選擇與投影交換律: 選擇和投影的順序可以隨意改變

  4. 選擇與笛卡爾積, 并, 自然連接, 差的分配律: 處在后面的選擇, 可以與處在前面的二目運(yùn)算順序進(jìn)行調(diào)整, 使得對相應(yīng)的表先實(shí)施選擇, 再實(shí)現(xiàn)連接等二目運(yùn)算. 這個非常重要, 是先選擇后進(jìn)行二目運(yùn)算的依據(jù), 又名"選擇提前".

  5. 選擇與笛卡爾積, 并的分配率: 可以先投影, 也可以先進(jìn)行二目運(yùn)算

還有幾個規(guī)則不是特別有用, 不敘述

3. 經(jīng)驗(yàn)性優(yōu)化五大策略

其實(shí)就是"選擇, 合并, 視圖"

  1. 選擇運(yùn)算盡可能先做, 這是最最最最重要和基本的, 這樣往往使得執(zhí)行代價減少了幾個數(shù)量級, 主要的原理就是選擇運(yùn)算能夠大大降低參與連接的元組的行數(shù), 使得連接生成的A?B結(jié)果也大大被縮小.

  2. 把選擇和投影運(yùn)算同時進(jìn)行, 如果有若干投影和選擇運(yùn)算, 并且他們都是針對同一個表, 那么可以在掃描這個表的時候同時完成這些所有的運(yùn)算, 以此避免重復(fù)掃描這張表.

  3. 把投影與其前或者后的雙目運(yùn)算(笛卡爾積, 等值連接, 并集, 差集)結(jié)合起來, 也就是說, 沒有必要為了選擇出幾個字段而單獨(dú)再重新掃描全表.

  4. 把某些選擇和在它前面要執(zhí)行的笛卡爾積結(jié)合起來成為一個連接運(yùn)算(比如變成等值連接), 這是因?yàn)檫B接運(yùn)算要比同樣情形下的笛卡爾積節(jié)省很多時間.
    杜老師說: "笛卡爾積原則上是不能自己執(zhí)行的!!!太浪費(fèi)了!!!"

笛卡爾積先進(jìn)行了 O(N ? M)操作 生成了A?B大小的中間文件, 存盤, 然后讀盤, 然后再按照where選擇進(jìn)行篩選得到結(jié)果; 對比之下, 等值連接運(yùn)算也進(jìn)行了O(N?M)操作, 但是還進(jìn)行了篩選, 只生成比較小的中間文件, 存盤和讀盤的是一個非常小的結(jié)果集合. 大大減少了IO開銷.

  1. 找出公共子表達(dá)式(一次計算, 多次使用). 比如很多的查詢都基于某個公共部分, 那么可以定義一個公共子表達(dá)式, 然后先計算一次公共子表達(dá)式, 然后把它存盤, 供其他大量的表達(dá)式來使用. 我們定義視圖其實(shí)就是在實(shí)踐這種策略.

4. 舉例子

1

這是一棵查詢樹, 從葉子端開始執(zhí)行, 最后合并到頂部, 產(chǎn)生一個唯一的結(jié)果.
默認(rèn)情況下, select sname from student and SC where student.sno = SC.sno and SC.sno = '2';就是這么構(gòu)建成查詢樹的.

2
3

四. 物理優(yōu)化

1. 基于經(jīng)驗(yàn)規(guī)則的優(yōu)化

對于小的表, 直接全表掃描, 即使列上有索引.
對于大的表, 如果是選擇條件涉及主鍵, 那么使用主鍵索引(MySQL等主流關(guān)系數(shù)據(jù)庫都會對主鍵建立索引);
如果不是涉及主鍵, 那么如果是等值查詢, 列上有索引, 就使用索引; 如果非等值查詢, 而是范圍值查詢, 那么范圍<=10%用索引, 范圍比較大的, 直接全表掃描.
And 和 OR: AND連接的, 優(yōu)先考慮使用索引; OR連接的, 優(yōu)先考慮使用順序掃描, 畢竟OR可能性非常多.

連接操作: 如果兩個表都按照連接屬性排序, 用sort-merge算法, 如果其中一個表在連接屬性上有索引,采用索引連接算法; 如果啥都沒有, 對小的表建立哈希表, 使用hash join方法; 或者使用基本的嵌套循環(huán), 不過外層循環(huán)(i循環(huán))使用小表, 這樣能稍微減小代價.

2. 基于代價的優(yōu)化

基于代價的優(yōu)化需要依賴數(shù)據(jù)庫表的各種"情報", 來計算出不同方案的代價, 從中選擇最優(yōu)的.
這些信息(meta info)包括:

  1. 對每個表來說:
    表的元組行數(shù) N,
    元組的長度, 即列的維度數(shù)目 P,
    表占用的block數(shù)目 B,
    表占用的溢出塊的塊數(shù) BO,

  2. 對表中的每個列,
    該列的不同值的個數(shù) k
    列的最大值, 最小值max, min
    列上有什么類型的索引 index: 按照實(shí)現(xiàn)方式有B+, Hash, Cluster / 按照類型來說有普通索引, 唯一索引, 主鍵索引, 聚集索引
    列上的數(shù)值分布情況 (直方圖)

那么對于不同情況, 我們有如下的代價估算:

  1. 全表掃描 cost = B

  2. 有索引的掃描
    如果選擇條件是key = value, 能適用唯一索引: L + 1
    如果選擇條件是attr = value, 能使用普通索引: L + S (可能有S個元組滿足)
    如果條件是范圍類的, 比如>, <, between A and B, 那么基本上就是接近全表掃描B;

  3. 連接算法的代價
    如果用嵌套循環(huán): 讀入Capacity-1塊B[a], 遍歷連接b表所有B[b], 再換下一批B[a], 直到a表結(jié)束. 所以, cost = B[a] + ( B[a]/(C-1) ) ? B[b] = a表IO次數(shù) + b表IO次數(shù), 假如要生成中間文件的話, 那么還得加上存下所有連接好的元組的磁盤IO開銷.

如果用sort-merge: cost = B[a] + B[b], 如果要把中間結(jié)果寫入外存, 那么還要加上存下所有連接好的元組的磁盤IO開銷, 這個開銷和上面嵌套循環(huán)的是一樣的.
假如表本身沒有排序, 那么排序的代價是B[a]logB[a] + B[b]logB[b]

參考資料

  1. 數(shù)據(jù)庫系統(tǒng)概論(高級篇)
  2. 腳本之家: SQL語句的各個關(guān)鍵字的解析過程詳細(xì)總結(jié)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內(nèi)容