又是一個可能會得罪其他單位的任務,在最近一次的專案中,為了改善現有系統效能不佳的問題,開始從不同Tier分別查起,最後發現應用程式對資料庫表格的查詢語法不當,導致資料處理的時間過久,結果造成網頁回應速度過慢。唉,又是SQL指令惹的禍!

其實程式設計師在不眠不休狂趕專案進度的狀況下,首要前提是功能上的需求能先被滿足,行有餘力才會考慮到效能問題。軟體專案經理既要固守優質軟體的理想,卻發覺實現的門檻愈來愈高,這樣的程式品質在系統上線初期也許還不會被發覺,當資料量日益成長之後,問題便慢慢浮現。

都是自動化惹的禍?

與資料層面有關的效能議題,除了資料庫系統本身的調校外,對於應用程式對資料庫進行存取的SQL語法,其實也是關鍵之一。

對於系統方面的調校,通常會落在DBA身上,而SQL的撰寫則是程式開發人員所需要了解。現在為了符合快速開發及方便使用的精神,在SQL語法的撰寫上, 常會透過語法產生器的方式來產生SQL查詢指令,若是遇到較複雜的結構時(像是多個資料表進行Join、多層次的子查詢Subquery、WHERE條件 組合繁多時),由特定工具所自動產生出來的語法是否能符合效能的要求,就有待商榷了。

先前筆者曾經介紹《Learning SQL》(可參見iThome電腦報第224期),該書屬於學習SQL的入門書,從最基本的觀念開始闡述。而這次針對SQL指令的優化,筆者找了兩本建議 閱讀的書籍:《SQL Tuning》及《SQL Performance Tuning》,兩本都是針對SQL指令效能調校議題深入討論的書籍,而且不限定於某一個廠牌的資料庫產品上,建議具備基本SQL使用經驗及資料庫系統概 念的讀者閱讀。

SQL調校不只是指令的善用,亦是查詢結構的改良

在O’reilly出版的《SQL Tuning》書中,你可以學習如何掌控你所撰寫的SQL指令的執行方式及背後的處理流程,利用作者所提出的查詢流程圖(Query Diagramming)獨特方法,將SQL的查詢語法以結構化流程圖的方式,抽絲剖繭呈現,幫助你在思考類似問題時,能加速找出癥結所在。

在本書的第二章中,便從資料庫系統的架構談起,探討了資料庫對於SQL查詢在執行時的內部作業流程,像是如何有效運用快取記憶體(Cache)來 加速執行效率、資料表在實體檔案系統中的儲存方式、資料讀取時其資料表的實際走訪方式、各式索引的結構及其產生的成本為何、以及在執行Join運算時的處 理過程。這裡提供了一些建議的設計原則,讓你可以將基礎概念搞清楚,才能充分掌握SQL內部運作的原理。

在SQL效能分析時,執行計畫(Execution Plan)常常被用來檢測SQL語法的適當性,成為找問題的工具。第三、四章教你如何使用、解讀、進而有效控制執行計畫,協助自己對SQL語法的改良。

另外,作者除了提出概括性的通則之外,針對目前市面上通行的三大品牌資料庫產品(Oracle、IBM DB2、MSSQL)也有分節介紹,可依你的需求選讀。

Query Diagramming為本書的核心思想

除了執行計畫進行效能分析,第五至七章所提到的查詢圖示法(Query Diagramming Method)便是本書作者所提出的核心思想。此分析技術透過一連串的點與線的組合,將SQL查詢語法拆解成圖,並標上在查詢語法中相關資料表的參考權重 數字,發掘可能發生的效能瓶頸所在。這樣的觀念類似演算法裡的Big O Notation,用來釐清程式邏輯的複雜度所造成的成本,找出執行最費時的地方。

這樣的方法論可依圖示內含資訊的完整度而分為:完整圖示法(Full Diagrams)以及簡易圖示法(Simplified Diagrams)。作者在本書中利用案例來逐步分解,將SQL指令轉化成4種不同的符號來表示:

● 節點(Node):用來表示資料庫中的資料表(Table),也就是SQL指令中在FROM子句的資料表。

● 連結(Link):代表資料表之間的關連性,以帶有箭頭的線條表示,方向意指關聯欄位之間的唯一性(Unique)。

● 有底線的數字:標註於節點旁,表示符合WHERE條件的記錄占該資料表的比例,以小於1的小數來表示。

● 無底線的數字:標註在連結的兩端,分別表示作者所定義的Master Join Ratio及Detail Join Ratio(詳細定義內容請參考本書)。

當然,還有一些你認為也會影響執行效能的變數(像是被SELECT的欄位內容、ORDER BY排序方式等)並沒有被納入,作者在本章也有詳細說明此分析工具設計的原因。

結合範例說明分析方法

基於這樣的分析工具,作者在第七章以實例演練說明更複雜的查詢語法,讓讀者更清楚如何落實這樣的分析工具。作者倡導此分析工具亦有他的理由,在第八章更以專章說明為何這樣的分析方式是有效的。

作者嘗試以標準的分析方法來處理所有的查詢問題,但遇到某些特例時,需要再延伸出不同的應用方式來處理。

第九章舉出一些特例狀況,並說明如何運用Query Diagramming的方式來進行分析,像是查詢成本甚高的OUTTER JOIN等。遇到連調校後也無法滿足的狀況時,作者則建議以其他方式(非單純調整SQL語法、回傳資料量過大時可以批次方式產出靜態結果,或是以強制性的 查詢條件,以及透過中介層軟體來配合加快執行速度等方式來改善)來補其不足。

值得一提的是,作者將從發現問題到尋得解法的整個處理流程,在附錄中以實例的方式從頭到尾完整地說明分析及處理的過程,有助於讀者熟悉理論如何落實到實際作法。

SQL最佳化的指令工具書

而Addison Wesley所出版的《SQL Performance Tuning》一書則是偏向SQL指令的撰寫原則討論,每個與查詢有關的關鍵字都被作者詳盡說明,全書花了不少篇幅討論如何寫出較好的SQL指令,你可以 逐章閱讀,或當成工具書,在實際寫作時查閱參考。本書內容的特點如下:

● 作者針對相同結果提供不同寫法的SQL指令,你可以比較個中差異,有助於了解每個指令的特性以及適合使用時機。

● 由於本書內容不綁定任何特定資料庫產品,因此,在每個指令的章節開始,作者都貼心地整理市面上知名資料庫系統對指令、運算式以及資料型態的支援狀況,避免讀者搞錯SQL的用法。

● 書中建議較佳的SQL指令撰寫方式,會在該指令下方加註GAIN: x/8的參考數據,表示該指令在本書所採用測試的8大DBMS產品中,在效能上表現相對較佳的比例。這樣的參考數字有助於了解一樣的寫法,在不同的 DBMS中是否仍表現優異,讓讀者了解該指令對DBMS實際的影響程度。

● 為求所撰寫的SQL指令能支援異質資料庫,本書倡導程式可攜性(Portability)的精神,利用ANSI-SQL落實到書中的每個範例中。

● 如果你想快速閱讀,每個章節後的結語(The Bottom Line)列出了該指令的使用建議及應該避免的用法,方便沒什麼時間仔細研讀的讀者使用。

雖然目前市面上所通行的資料庫系統產品,號稱已對SQL命令的執行進行最佳化的設計,意謂程式設計人員不需要花太多心思在SQL語法本身效能的改 善,這樣可能造成意想不到的結果。若開發人員也能建立正確的設計觀念,在設計階段就納入考量,未來可能引發的問題也就能被減少許多。

不同時機妥善運用,讓你如虎添翼

這次介紹的兩本書使用時機各有不同。《SQL Performance Tuning》在於讓程式開發人員奠定良好的SQL指令實作基礎,在系統實作初期即能引用較佳的撰寫方式進行開發,避開不良設計,在有限的測試資料數量及 資料本身下,先行達到某一水準;在壓力測試進行時餵入大量測試資料後,以《SQL Performance Tuning》中提到的分析工具,來檢視原本設計的SQL語法是否有效能上的疑慮,找出問題所在進而改善。

在不同的專案時機點搭配兩本書的閱讀,相信可以讓你對自己寫出來的SQL指令更具信心!總而言之,還是那句老話:「程度不只是要寫得出來,還要寫得好!」

《Learning SQL》

《Learning SQL》

SQL(Structured Query Language)是一種程式語言,它可以在命令模式下讓使用者與資料庫系統進行交談式互動,或者是編寫成程式檔(SQL Script)執行。它的語法簡單直覺,容易學習且快速上手。發展至今已經約三十餘年,廣泛流行的程度不減當年。

市面上流行的資料庫系統產品眾多,但以SQL進行資料操作的基本精神不變,每個產品為提供使用者更方便更有效的資料庫系統功能,除了標準ANSI SQL外,還會提供屬於自家產品特有的SQL語法及函式,像Oracle的PL/SQL、Microsoft SQL Server的T-SQL等。有鑑於初學者常常會因此而混淆,甚至混用,在本書介紹的SQL語法為ANSI標準,可適用於任何支援標準SQL語法的資料庫 系統上。

本書的定位為基礎入門書籍,所以會從最基本的觀念開始闡述。研讀本書你不需要有任何資料庫的基本觀念,作者以深入淺出循序漸近的方式,將你帶入資 料庫領域的大門。在書中採用的實作案例,是採用免費的MySQL資料庫系統做為練習平臺,透過實際操作讓你對SQL語法更有感覺。

結構化查詢語言,簡單得讓你可以立即上手
第一章先從SQL過去的歷史背景及演進過程談起,介紹關連式資料庫的基本觀念及一些重要名詞。第二章開始就以實作方式,介紹如何透過MySQL進 行資料庫系統的操作,教你如何一步一步以SQL命令建立資料庫,建立及變更資料表(Table)結構,資料型態的差異,資料的增刪修改等。

由於資料查詢功能是SQL語法的精華所在,第三、四、五章說明如何從資料庫找出你要的資料,這就提到SELECT語法的結構及相關撰寫方式,如何 搭配SQL提供的函式形成所需的過濾條件,以及跨多個資料表的存取方式。這裡會談到許多實用的細節,利用Join方式從一個以上的資料表找出關連性,這也 會是許多報表設計時常會運用到的重要觀念。而Join的方式亦有許多方式,在第十章可以找到完整的用法說明。

第六章介紹如何運用集合(Set)的概念融入資料操作上,第七章介紹對於不同型態資料(字元、數值、日期等)的處理方式,其間的轉換方式為何,另外第八章提到利用群組化(Grouping)及聚集(Aggregate)的功能,對資料進行分組運算,產生簡單的統計結果。

當你的資料無法單純以一個查詢語法得出,子查詢(Subquery)便可以幫你解決。第九章介紹子查詢的使用方式,它可以當成另一個查詢的資料來 源,或過濾條件值,它亦是為十分實用的語法。而條件判斷的機制,在第十章介紹了CASE的用法,可以根據變數值來決定不同的處理。

在多人同時使用資料庫系統時,交易管理機制就十分重要。第十二章便介紹交易的意義,利用不同形式的資料鎖定方式,透過交易機制針對資料一致性及完整性上達到有效控制。第十三章談到資料的正確性亦可以透過限制來防微杜漸,透過建立索引來提昇資料庫查詢的效率。

SQL入門者的良伴,與實作相結合
只要你的工作會接觸到資料庫,不管是開發應用系統,或負責系統管理工作,或是製作分析報表,就會與SQL脫離不了關係。在實務上有很多報表產生工 具或是整合性開發環境,都提供自動產生SQL命令的強大功能,但身為IT從業人員的你,能深入了解SQL命令的用法,對於資料結構的關連性及資料操作的觀 念才會有更全面的了解。

介紹SQL的書實在太多,你或許會問:這本書到底那兒值得推薦?像是類似指令集、參考手冊的內容,只能在需要的時候當成字典般地查閱,所獲得的資 訊也較為零散,並非學習導向,通常是讀過即忘。本書內容架構以教材方式編寫,可以當成教師們授課教材,每章後面亦提供練習題目,章節規劃即為作者建議的學 習順序。也許是定位為入門書的關係,本書並非提及與DBA維護工作(像是Backup/Restore)有關的內容,以及如何撰寫Trigger及 Stored Procedure。若是這些內容也一併包含,就再完美也不過了。

Follow

Get every new post delivered to your Inbox.