數據庫查詢優化(下)

7.用排序來取代非順序存取
非順序磁盤存取是最慢的操作,表現在磁盤存取臂的來回移動。SQL語句隱藏了這一情況,使得我們在寫應用程序時很容易寫出要求存取大量非順序頁的查詢。
有些時候,用數據庫的排序能力來替代非順序的存取能改進查詢。
              
實例分析 

下面我們舉一個製造公司的例子來說明如何進行查詢優化。製造公司數據庫中包括3個表,模式如下所示:
1.part表
零件號零件描述其他列
(part_num)(part_desc)(other column)
102,032Seageat 30G disk……
500,049Novel 10M network card……
……
2.vendor表
廠商號廠商名其他列
(vendor _num)(vendor_name) (other column)
910,257Seageat Corp……
523,045IBM Corp……
……
3.parven表
零件號廠商號零件數量
(part_num)(vendor_num)(part_amount)
102,032910,2573,450,000
234,423321,0014,000,000
……
下面的查詢將在這些表上定期運行,併產生關於所有零件數量的報表:
SELECT part_desc,vendor_name,part_amount
FROM part,vendor,parven
WHERE part.part_num=parven.part_num
AND parven.vendor_num = vendor.vendor_num
ORDER BY part.part_num
如果不建立索引,上述查詢代碼的開銷將十分巨大。爲此,我們在零件號和廠商號上建立索引。索引的建立避免了在嵌套中反覆掃描。關於表與索引的統計信息如下:
表行尺寸行數量每頁行數量數據頁數量
(table)(row size)(Row count)(Rows/Pages)(Data Pages)
part15010,00025400
Vendor1501,000 2540
Parven13 15,000300 50
索引鍵尺寸每頁鍵數量頁面數量
(Indexes)(Key Size)(Keys/Page)(Leaf Pages)
part450020
Vendor45002
Parven825060
看起來是個相對簡單的3表連接,但是其查詢開銷是很大的。通過查看系統表可以看到,在part_num上和vendor_num上有簇索引,因此索引是按照物理順序存放的。parven表沒有特定的存放次序。這些表的大小說明從緩衝頁中非順序存取的成功率很小。此語句的優化查詢規劃是:首先從part中順序讀取400頁,然後再對parven表非順序存取1萬次,每次2頁(一個索引頁、一個數據頁),總計2萬個磁盤頁,最後對vendor表非順序存取1.5萬次,合3萬個磁盤頁。可以看出在這個索引好的連接上花費的磁盤存取爲5.04萬次。
實際上,我們可以通過使用臨時表分3個步驟來提高查詢效率:
1.從parven表中按vendor_num的次序讀數據:
SELECT part_num,vendor_num,price
FROM parven
ORDER BY vendor_num
INTO temp pv_by_vn
這個語句順序讀parven(50頁),寫一個臨時表(50頁),並排序。假定排序的開銷爲200頁,總共是300頁。
2.把臨時表和vendor表連接,把結果輸出到一個臨時表,並按part_num排序:
SELECT pv_by_vn,* vendor.vendor_num
FROM pv_by_vn,vendor
WHERE pv_by_vn.vendor_num=vendor.vendor_num
ORDER BY pv_by_vn.part_num
INTO TMP pvvn_by_pn
DROP TABLE pv_by_vn
這個查詢讀取pv_by_vn(50頁),它通過索引存取vendor表1.5萬次,但由於按vendor_num次序排列,實際上只是通過索引順序地讀vendor表(40+2=42頁),輸出的表每頁約95行,共160頁。寫並存取這些頁引發5*160=800次的讀寫,索引共讀寫892頁。
3.把輸出和part連接得到最後的結果:
SELECT pvvn_by_pn.*,part.part_desc
FROM pvvn_by_pn,part
WHERE pvvn_by_pn.part_num=part.part_num
DROP TABLE pvvn_by_pn
這樣,查詢順序地讀pvvn_by_pn(160頁),通過索引讀part表1.5萬次,由於建有索引,所以實際上進行1772次磁盤讀寫,優化比例爲30∶1。筆者在Informix Dynamic Sever上做同樣的實驗,發現在時間耗費上的優化比例爲5∶1(如果增加數據量,比例可能會更大)。

小結

20%的代碼用去了80%的時間,這是程序設計中的一個著名定律,在數據庫應用程序中也同樣如此。我們的優化要抓住關鍵問題,對於數據庫應用程序來說,重點在於SQL的執行效率。查詢優化的重點環節是使得數據庫服務器少從磁盤中讀數據以及順序讀頁而不是非順序讀頁。  

發佈了14 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章