mysql 查詢優化器 資料庫查詢優化器

2021-10-18 02:43:47 字數 3074 閱讀 8093

所謂查詢優化,目標是關聯式資料庫下或者 newsql 的 sql server 層對 sql 語句進行優化,在不改變期望結果的情況下使得資料庫引擎計畫執行時間最短。狹義的查詢優化技術是指邏輯優化與物理優化(在後面會細講),廣義上的查詢優化技術包括從 sql 語句輸入開始,對 sql 語句的重寫,內部執行演算法的優化,並行優化及分布式條件下的優化,還包括了外部快取機制對於查詢計畫及查詢結果的重用。

查詢優化技術是資料庫領域十分重要的技術,尤其在當前業務資料及業務請求規模不斷增長的情況下顯得尤為重要。這裡從狹義的查詢優化技術入手,從巨集觀上講述查詢優化器的架構及各個模組實現的主要功能任務,希望能夠對大家了解及理解查詢優化器有所幫助。

架構sql 語句經過語法分析器生成語法分析樹,再通過查詢優化器生成查詢樹及查詢計畫,最後交由執行器執行。

架構圖語法分析器

語法分析

語法分析是指對使用者輸入的 sql 語句進行判斷,糾正拼寫錯誤及語法錯誤。如:

select name, class_name

from student s, course c, sc sc

where s.sno = sc.sno and c.cno = sc.cno and c.cno = 22;

語義檢查

語義檢測負責判斷 sql 語句中涉及的表及表中的屬性列是否存在,如果 sql 所操作的目標表或者屬性列完全不存在那麼後期的優化也是徒勞無果的。比如在上面的 sql 例子中,將會判斷以下儲存物件或元資料是否存在。

屬性列: name, class_name

查詢優化器

邏輯優化

邏輯優化簡單來說就是根據關係代數的等價變換規則進行查詢重寫。首先傳統關係代數運算子有並、交、差、積,對於 sql 語句來說,專有運算子有選擇、投影、連線、除。首先傳統運算子在 sql 語句中的體現為:

並 - union

select * from r union select * from s

交 - not in(not in)

select * from r where kr not in (

select kr from r where kr not in (

select ks from s))

差 - not in

select * from r where kr not in (select ks from s)

積 - 無條件join

select r.* , s.* from r , s

專有運算子的 sql 表現:

選擇 - condition

select * from r where condition

投影 - 屬性列

select col_1,col_2+2 from r

連線 - condition 中 join 或者等值連線

select r.col_1,s.col_2 from r,s where condition

除 - not exists(not exists)

select distinct r1.x from r,r1 where not exists (

select s.y from s where not exists (

select * from r r2 where r2.x=r1.x and r2.y=s.y))

有了上述的運算子對應關係, sql 語句就可以使用關係代數的等價變換進行優化。這裡有一些例子:

邏輯優化舉例

物理優化

物理優化是與實際儲存相關的優化階段。簡單來說就是通過代價模型對錶級操作演算法的選擇。

首先介紹代價模型,學過計算機系統結構的同學都知道,衡量計算機效能的重要指標就是相同任務或者指令的執行時間。那麼與之相似,乙個執行計畫的優劣程度也可以使用時間來衡量。當然,資料庫查詢優化的目標也是在盡可能短的時間返回期望的結果。所以代價模型的巨集觀表示式為:總代價 = io代價 + cpu代價

說回表級操作演算法,這裡有以下3類:

單錶 ---> 掃瞄方式 : 全表掃瞄、索引掃瞄

兩表 ---> 連線方式 : 巢狀迴圈連線、歸併連線、雜湊連線

多表 ---> 連線順序 : 動態規劃、啟發式、貪心、system r、遺傳演算法

單錶掃瞄

單錶掃瞄的選擇主要通過選擇率來判斷,也就是滿足條件的元組數(表中一行資料)佔總元組數的比例。同時在許多文章中,這裡滿足條件的元祖數也稱為基數,有: 選擇率 = 基數 / 總元組數。

比如在條件篩選過後可能只有 1/1000 的元組被選到,那麼通過索引掃瞄的方式訪問整個表是很快的,但如果有 999/1000 的資料將會被篩選出來,那麼通過全表掃瞄的方式或許更加有效。

兩表連線

傳統的兩表連線方法有巢狀迴圈連線、歸併連線及雜湊連線。

巢狀迴圈連線 : 相當於兩個for迴圈,使用 a 表的乙個元組去匹配 b 表的每乙個元組,直到 a 表的所有元組都被訪問完全。

雜湊連線 : 先將 a 表所有元組對應屬性列 hash ,然後將 b 表的每個元組對應屬性列使用相同的雜湊方法 hash,若值相等則匹配。

多表連線順序

多表下是對各個表的連線順序進行選擇,比如 a、b、c 三個表,a、b 較大,c 較小,那麼 ab 先連線可能產生的中間結果會比較大, 採用 bc-a 的連線順序可能先得到的中間結果就會比較小,既節省計算資源又節省儲存空間。常見的多表連線順序的選擇演算法有動態規劃、啟發式、貪心、system r、遺傳演算法。postgresql 中使用的演算法為動態規劃及遺傳演算法。

分布式查詢優化

與單機的查詢優化不同,分布式情況下目標資料可能分布在不同的節點上。因此對於代價模型來說,還需要加上資料傳輸的代價。同時由於分布式環境的複雜性,還要考慮到資料副本及底層資料庫引擎異構(如關係型與 nosql )和異制(資料模型及資料結構不相同,比如檔案型及 kv)的問題。

分布式環境下如果兩個要連線的表(a、b)在不同的節點上,這樣的情況下有兩種基本的連線演算法:

直接連線:直接將 b 表整個傳輸到 a 表所在節點進行連線計算

半連線:只是將 b 表要連線的屬性列傳輸到 a 表所在節點進行連線計算,計算完畢後傳輸回 b 表的節點篩選出匹配完成的元組

很明顯,直接連線不適合目標表非常大的情況,但是半連線傳輸的次數較多。

最後以上旨在幫助大家巨集觀認識資料庫查詢優化器,對查詢優化器架構及各個模組功能有大體認識。

mysql 資料庫查詢優化

合理選擇表字段型別型別 int型別優先於varchar型別 優先於text型別 varchar 變長字串 型別優先於char 不可變長 型別 表分割 對於頻繁使用的且資料量增長很快的表進行表的分割 水平分割 當一張表資料量非常大影響效率時,可將表中的資料按一定的演算法將其進行水平方向 行 的分割,如...

mysql 資料庫查詢優化

從上圖可以看出,計算機系統硬體效能從高到代依次為 cpu cache l1 l2 l3 記憶體 ssd硬碟 網路 硬碟 根據資料庫知識,我們可以列出每種硬體主要的工作內容 cpu及記憶體 快取資料訪問 比較 排序 事務檢測 sql解析 函式或邏輯運算 網路 結果資料傳輸 sql請求 遠端資料庫訪問 ...

mysql資料庫查詢優化

上兩周一直想辦法提高查詢速度,取得一點效果,解決了部分問題,記下來以便將來自己檢視。由於公司沒有專門的dba,我自己對mysql資料庫也不是很熟悉,而且這個j a開發的網路審計系統的管理系統,是經過了n多人幾年時間的修修改改,今天到我們手裡,要改成能支援大流量情況的版本,所以對我們這個只有幾個人的j...