SELECT LASTNAMEFROM EMPWHERE EMPNO = '000010';
想想看:當訪問文件中的數據時,程序員必須編碼指令來打開文件、開始一個循環、讀取記錄、檢查 EMPNO 字段是否等于適當的值、檢查文件結尾、回到循環的開頭等?! QL 本來就是非常靈活的。它使用自由格式的結構,該結構可以讓用戶開發 SQL 語句來適合他們的需要。DBMS 在執行之前會分析每個 SQL 請求,以檢查語法是否正確和優化該請求。SQL 語句不需要從任何給定的列中開始,您可以將它們串在一行中,或者把它們拆成幾行。例如,以下這條單行的 SQL 語句與我前面使用的三行示例等價:SELECT LASTNAME FROM EMP WHERE EMPNO = '000010';
SQL 的另一個靈活特性是您可以用許多形式不同但功能等價的方法來制定一個請求。例如:SQL 可以連接表或嵌套查詢。您始終可以將嵌套查詢轉換成等價的連接。您可以在大量的函數和謂詞中看到這一靈活性的其它示例。具有等價功能的特性的示例包括: BETWEEN vs <= / >= IN vs 一系列和 OR 配合的謂詞 INNER JOIN vs FROM 子句中串在一起并用逗號分隔的表 OUTER JOIN vs 帶有 UNION 的簡單 SELECT 和相關的子查詢 CASE 表達式 vs 復雜的 UNION ALL 語句 SQL 展示的這一靈活性并不總是稱心的,因為形式不同但功能等價的 SQL 公式可以提供非常不同的性能。我將在本文的以后部分討論該靈活性所造成的結果,并提供開發有效的 SQL 的準則?! ∪缥宜f的,SQL 指定了要檢索或操作什么數據,但沒有指定數據庫如何完成這些任務。這就使 SQL 本身變得很簡單。假如您能夠記得關系數據庫的一次處理一個集合(set-at-a-time)的特點,您就開始把握 SQL 的本質和性質了。一條 SQL 語句可以作用于多行。作用于一組數據而不需要建立如何檢索和操作數據的能力將 SQL 定義成非過程化語言 上一頁12345678下一頁 因為 SQL 是一種非過程化語言,所以一條語句可以代替一系列過程。同樣,由于 SQL 使用集合級別的處理以及 DB2 優化查詢來確定數據導航邏輯,所以這是可能的。有時,假如不使用 SQL 語句,一條或兩條 SQL 語句可以完成的任務就需要完整的過程化程序來完成?! 灮鳌 灮魇?DB2 的心臟和靈魂。它分析 SQL 語句并確定可以滿足每條語句的最有效的存取路徑(請參閱圖 1)。DB2 UDB 通過解析 SQL 語句來確定必須訪問哪些表和列,從而完成該操作。DB2 優化器然后查詢存儲在 DB2 系統目錄中的系統信息和統計信息,以確定完成滿足 SQL 請求所必需的任務的最佳方法?! D 1. 運行中的 DB2 優化SELECT LASTNAME,SALARY FROM EMP WHERE EMPNO = '000010' AND DEPTNO = 'D01'
什么索引會對這個簡單查詢有作用?首先,考慮您可以創建的所有可能的索引。您的第一個簡短列表可能看起來如下: EMPNO 上的 Index1 DEPTNO 上的 Index2 EMPNO 和 DEPTNO 上的 Index3 這是一個好的開始,Index3 可能是最好的。它讓 DB2 使用索引來立即查找滿足 WHERE 子句中的兩個簡單謂詞的行。當然,假如您已經有許多關于 EMP 表的索引,您也許應該檢查再創建另一個關于表的索引所帶來的影響。要考慮的因素包括: 修改影響 :DB2 將自動維護您創建的每個索引。這表示對該表的每個 INSERT 和每個 DELETE 都將不僅在表中插入和刪除,而且會在其索引中插入和刪除。假如您對在索引中的列的值進行 UPDATE 操作,那么您還更新了該索引。因此索引加快了檢索過程的速度,但減慢了修改的速度。 上一頁12345678下一頁 現有索引中的列 :假如在 EMPNO 或 DEPTNO 上已經有了一個索引,那么創建另一個關于該組合的索引也許并不明智。但是,更改另一個索引以添加缺少的列也許可以起作用。但也不一定,因為索引中列的順序也許會根據查詢而有很大差異。例如,考慮以下查詢:SELECT LASTNAME, SALARYFROM EMPWHERE EMPNO ='000010'AND DEPTNO > 'D01';
在這種情況下,在索引中應該首先列出 EMPNO。然后列出 DEPTNO,從而答應 DB2 對第一列(EMPNO)執行直接索引查找,然后針對大于號掃描第二列(DEPTNO)?! 《遥偃缫呀洿嬖陉P于這兩列的索引(一個關于 EMPNO,一個關于 DEPTNO),DB2 可以使用它們來滿足該查詢,因此創建另一個索引也許是沒有必要的?! ∵@種特定查詢的重要性 :查詢越重要,那么您可能就越應該通過創建索引來進行調優。假如您正在編碼 CIO 要天天都運行的查詢,那么您應該確保它提供最佳性能。因此,為該特定查詢構建索引是很重要的。反之,職員的查詢也許就沒有必要看得那么重,所以也許應該利用現有索引來執行查詢。當然,決定取決于應用程序對業務的重要性 - 而不只是用戶的重要性。 索引設計涉及的內容比到目前為止我所討論的要多得多。例如,您也許要考慮索引重載以實現僅索引訪問(index-only access)。假如 SQL 查詢要尋找的所有數據都包含在索引中,那么 DB2 也許只使用索引就可以滿足該請求。請考慮我們前面的 SQL 語句。給定了關于 EMPNO 和 DEPTNO 的信息,我們要尋找 LASTNAME 和 SALARY。我們還從創建關于 EMPNO 和 DEPTNO 列的索引開始。假如我們在索引中還包含了 LASTNAME 和 SALARY,我們就不再需要訪問 EMP 表,因為我們需要的所有數據都已經在索引中。該技術可以大大提高性能,因為它減少了 I/O 請求的數量。 上一頁12345678下一頁 請記?。菏姑總€查詢成為僅索引訪問是不謹慎,甚至也是不可能的。您應該謹慎使用該技術以便用于非凡棘手或重要的 SQL 語句。 SQL 編碼準則 當您編寫訪問 DB2 數據的 SQL 語句時,要確保遵循以下三個編碼 SQL 的準則以獲得最佳性能。當然,SQL 性能是一個復雜的話題,而且了解 SQL 的執行方式的每一個細微差別可能要花一生的時間。但是,這些簡單的規則可以使您進入開發高性能 DB2 應用程序的正軌?! 〉谝粭l規則是始終在每條 SQL SELECT 語句的 SELECT 列表中只提供 確實需要檢索的那些列 。另一種說法就是“不要使用 SELECT *”。簡寫 SELECT * 表示您要檢索正在被訪問的表中的所有列。這適用于“快捷但不恰當的方式獲得的“(quick and dirty)查詢,但卻是應用程序的壞實踐,因為: DB2 表在將來可能需要更改,以包括附加列。SELECT * 也會檢索那些新的列,而假如沒有進行費時的更改,您的程序也許無法處理附加的數據?! B2 將為被請求返回的每一列消耗附加資源。假如程序不需要數據,它就不會尋找它。即使程序需要每一列,最好根據 SQL 語句中的名稱來顯式地尋找每一列,以便增加清楚度和避免以前犯的錯誤。 不要尋找您已經知道的東西 。這聽起來似乎顯而易見,但大多數程序員都曾經違反過這條規則。舉一個典型的示例,考慮以下 SQL 語句有什么錯誤:SELECT EMPNO, LASTNAME, SALARYFROM EMPWHERE EMPNO = '000010';
放棄嗎?問題是 EMPNO 已經包含在 SELECT 列表中。您已經知道了 EMPNO 將等于值“000010”,因為那就是 WHERE 子句要 DB2 做的事。但在 WHERE 子句中列出了 EMPNO,DB2 還會盡職地檢索該列。這會產生附加開銷,從而降低性能。 上一頁12345678下一頁 在 SQL 中 使用 WHERE 子句過濾數據 ,而不是在程序中到處使用它進行過濾。這也是新手輕易犯的錯誤。在 DB2 將數據返回到程序之前,最好由 DB2 過濾數據。這是因為 DB2 使用附加 I/O 和 CPU 資源來獲取每一行數據。傳遞到程序的行越少,SQL 的效率就越高:SELECT EMPNO, LASTNAME, SALARYFROM EMPWHERE SALARY > 50000.00;
與只讀取所有數據而不使用 WHERE 子句,然后在程序中檢查 SALARY 是否大于 50000.00 的做法相比,該 SQL 更好?! ∈褂脜祷樵?。參數化 SQL 語句包含了變量,也稱作參數(或參數標記)。典型的參數化查詢使用這些參數來代替文字值,因此 WHERE 子句條件可以在運行時更改。通常程序被設計成最終用戶可以在運行查詢之前提供參數的值。這答應使用一個查詢根據提供給參數的不同的值返回不同的結果?! 祷樵兊闹饕阅芎锰幨莾灮骺梢灾贫ㄔ谥貜蛨绦姓Z句時能夠再使用的存取路徑。與每次 WHERE 子句中需要一個新值就發出一條全新的 SQL 語句相比,這可以給程序增加很大的性能收益?! 〉牵@些規則并不是 SQL 性能調優的最終和最高目標 - 決不是。您可能需要附加的、深入的調優。但遵循前面的規則將確保您不會犯降低應用程序性能的“新手”錯誤。 特定數據庫應用程序開發技巧 無論您使用的是 Delphi、C++Builder 還是 Kylix,某些技巧和準則將幫助您確保在訪問 DB2 數據時獲得好的性能。例如,在某些情況下,使用 dbExPRess TM來代替 ODBC/JDBC 或 ADO 可以提高查詢性能。dbExpress 是用于從 Delphi(或 Borland Kylix™)處理動態 SQL 的跨平臺接口?! ∫_保在您的應用程序中經常發出 COMMIT 語句。COMMIT 語句控制工作單元。發出 COMMIT 會將自上一個 COMMIT 語句之后的所有工作“永遠”記錄到數據庫中。在發出 COMMIT 之前,可以使用 ROLLBACK 語句回滾工作。當修改數據(使用 INSERT、UPDATE 和 DELETE)但沒有發出 COMMIT 時,DB2 將在數據上加一把鎖并保持該鎖 - 這把鎖會使其它應用程序在等待檢索被鎖住的數據時超時。通過在工作完成時發出 COMMIT 語句,并且確保數據是正確的,就釋放了該數據以供其它應用程序使用?! ×硗猓瑯嫿☉贸绦驎r要考慮使用情況。例如,當某個特定查詢返回幾千行給最終用戶時,要慎重處理。對于在程序和最終用戶之間的在線交互,很少會用到幾百行以上的數據。您可以在 SQL 語句上使用 FETCH FIRST nROWS ONLY 子句來限制返回到查詢的數據量。例如,考慮以下查詢:SELECT EMPNO, LASTNAME, SALARYFROM EMPWHERE SALARY >
10000.00FETCH FIRST 200 ROWS ONLY;
該查詢將只返回 200 行。假如有超過 200 行符合條件也沒有關系;假如您嘗試從查詢中 FETCH(訪存)超過 200 行,DB2 將用 +100 SQLCODE 表明數據結束。當您想要限制返回給程序的數據量時,這種方法很有用?! B2 支持另一個名為 OPTIMIZE FOR nROWS 的子句,該子句不限制要返回給游標的行數,但從性能角度看可能是有幫助的。使用 OPTIMIZE FOR nROWS 子句告訴 DB2 如何處理 SQL 語句。例如:SELECT EMPNO,LASTNAME,SALARYFROM EMPWHERE SALARY >
10000.00OPTIMIZE FOR 20 ROWS;
這告訴 DB2 嘗試盡快訪存前 20 行。假如您的 Delphi 應用程序在顯示從數據庫檢索出來的數據行時每次顯示 20 行,那么這將非常有用?! τ谥蛔x游標,使用 FOR READ ONLY 子句確保游標無歧義。Delphi 不能在 DB2 游標中執行位置更新,因此將 FOR READ ONLY 附加到每條 SELECT 語句后面可以使游標成為無歧義的只讀游標,從而對 DB2 有所幫助。例如:SELECT EMPNO,LASTNAME, SALARYFROM EMPWHERE SALARY > 10000.00FOR READ ONLY;
上一頁12345678 新聞熱點
疑難解答