20120627db2數據庫基礎、設計與優化

鑑於CSDN無故刪除博文,本博客不再更新,暫時遷至http://www.db365.net


商業智能羣199567325,2012年6月27號《db2數據庫基礎、設計與優化》,講解者:趙堅密Jimmy。

講課方式,YY頻道號:85536471

課件材料《大數據量數據整合與查詢性能優化(DB2V9& AIXV5.3)v1.2 - 副本.pdf》,可從以下地址免費下載:http://wenku.baidu.com/view/21929d95daef5ef7ba0d3c6d.html


此YY頻道每週三講解,具體請加QQ羣21025718下載講課錄音。


大數據量數據整合與查詢性能優化(修訂)

趙堅密([email protected]

前言

本文適用操作系統平臺爲IBM AIX 5.3,也可用於一般UNIX平臺;數據庫爲IBM DB2,版本9.1文中引用了筆者在金宏工程外匯管理局整合數據庫、統計分析系統和綜合查詢子系統的開發經驗。本文的題目就來自於這樣一個背景,因爲整合庫系統是一個大數據量數據整合系統,綜合查詢和統計分析系統是大數據量的查詢系統,所以將本文命名爲《大數據量數據整合與查詢性能優化》。本文只考慮單一節點的數據庫,沒有討論數據庫集羣。

關於性能優化有兩大目標:(1)如何充分調動系統資源;(2)採取何種方案使得達到某一目的而消耗的系統資源最少。第一個目標是要提高系統資源利用率;第二個目標是要確保對資源的利用是高效的。

硬件產品的升級非常快,商用服務器通常是多核,多硬盤的。現今,就連家用機也配備了多核。如金宏工程採購的IBM小型機,便是多核的,中等配置爲8CPU、32GB內存,稍高的配置爲16CPU,甚至更高。而硬盤則是RAID5磁盤陣列,通常一臺機器10塊盤,或更多。

提高並行性便能很好的調動系統資源。通常從兩個方面可以提高並行性:(1)幾件事並行的做;(2)一件事使用多個處理器來做。在系統設計時,對處理流程進行優化,讓多個獨立的過程並行執行,從而佔用多個處理器,提高處理器的利用率。在性能測試環境,或者生產環境上需要調整系統或者應用的相關參數,使得一個過程也能佔用多個處理器,進一步提高處理器的利用率。

“消耗更少的系統資源,來完成相同的事情”是所有程序員追求的目標。爲了完成這一目標,程序員們不斷優化自己的代碼,甚至不惜徹底的改變程序的核心算法。

對於SQL代碼的優化,通常處於硬件、操作系統、數據庫管理系統等優化之後。

爲了更好的達到這一目標,通常要求程序員有很好的代碼書寫習慣,第一次就寫出優良的代碼。優化時,只要考慮算法的優化即可。算法的優化也不是盲目的,通常針對那些“需要優化的部分”來進行。“需要優化的部分”就是那些影響整體性能的,影響整體進度的,處於“關鍵路徑”上的過程。

代碼和算法的優化也是性能優化的重要方面。但這個方面不是本文介紹的重點。

閱讀說明

本文主要面向數據庫設計和開發人員、部署人員和性能調優人員。


目錄

前言...- 1 -

閱讀說明...- 1 -

1 DB2數據庫基本概念... - 4 -

1.1 數據庫對象... - 4 -

1.1.1 實例... - 5 -

1.1.2 數據庫... - 5 -

1.1.3 節點組... - 5 -

1.1.4 表... - 5 -

1.1.5 視圖... - 5 -

1.1.6 索引... - 5 -

1.1.7 模式... - 7 -

1.1.8 系統目錄表... - 7 -

1.2 存儲器對象... - 7 -

1.2.1 表空間... - 7 -

1.2.2 容器... - 9 -

1.2.3 緩衝池... - 9 -

2 表空間存儲... - 10 -

2.1 AIX系統存儲管理簡介... - 10 -

2.2 裸設備和文件系統... - 11 -

2.3 系統管理和數據庫管理... - 12 -

2.4 如何合理創建表空間設備... - 13 -

2.4.1 原則... - 13 -

2.4.2 表空間容器的創建方法... - 13 -

2.4.3 整合數據庫表空間設備情況... - 14 -

2.5 建庫語句參考... - 14 -

3 緩衝池和表空間... - 16 -

3.1 緩衝池... - 16 -

3.2 緩衝池大小... - 16 -

3.3 表空間頁大小... - 16 -

3.4 系統臨時表空間... - 17 -

3.5 區段大小和預取大小... - 17 -

3.5.1 區段大小... - 18 -

3.5.2 預取大小... - 18 -

4 提高SQL語句執行效率... - 19 -

4.1 建立索引... - 19 -

4.2 採用表分區... - 20 -

4.3 運行統計和重組... - 21 -

4.3.1 通過運行統計來收集索引信息... - 21 -

4.3.2 存儲過程裏執行運行統計語句... - 22 -

4.3.3 重組表中的數據... - 23 -

4.4 減少對數據庫的更新和刪除操作... - 23 -

4.4.1 更新操作... - 23 -

4.4.2刪除操作...- 25 -

4.5 如何使訪問更高效... - 28 -

5 參數調優... - 29 -

5.1 AIX系統... - 29 -

5.2 DB2環境變量... - 30 -

5.3 DB2數據庫實例參數... - 30 -

5.4 DB2數據庫參數... - 31 -

6 開始行動... - 32 -

6.1 用topas監控硬件使用情況... - 32 -

6.2 從執行時間來確定主要矛盾... - 32 -

6.3 進一步觀察以決策... - 33 -

6.3.1 DB2 Visual Explain. - 33 -

6.3.2 DB2exfmt- 36 -

6.3.3 DB2expln. - 37 -

6.3.4 錶快照監視器... - 37 -

6.4 不同數據庫處於不同實例... - 37 -

6.5 開始行動... - 38 -

7 參考文獻... - 39 -

8索引...- 40 -

8.1索引與目錄...- 40 -

8.2影響索引作用的因素...- 40 -

8.2.1區分度(檢索比率)...- 40 -

8.2.2聚集度...- 41 -

8.2.3表大小...- 41 -

8.2.4業務類型...- 41 -

8.2.5函數與索引...- 42 -

8.3索引開銷...- 42 -

8.4索引總結...- 43 -

9 SQL語句編寫(DB2)... - 45 -

9.1謂詞...- 45 -

9.2多餘的連接...- 46 -

9.3子查詢...- 46 -

9.4外連接...- 47 -

9.5 UNION ALL的使用... - 47 -

9.6 Having子句... - 48 -

9.7 OFNR和FFNR子句... - 48 -

9.8使用參數標記...- 48 -

 


1 DB2數據庫基本概念

1.1 數據庫對象

關鍵的數據庫對象包括:實例、數據庫、節點組、表、視圖、索引、模式、系統目錄表。圖1顯示了一些數據庫對象之間的關係。它也顯示了表、索引和長整型數據存儲在表空間中的情況。

圖1. 一些數據庫對象之間的關係

 

1.1.1 實例

實例(有時稱爲數據庫管理程序)是管理數據的DB2代碼。它控制可對數據執行的操作,並管理分配給它的系統資源。每一個實例都是一個完整的環境。一個實例有它自己的數據庫(其他的實例不能存取它)。它還有獨立的安全性,不受同一機器(系統)上其他實例的影響。

1.1.2 數據庫

關係數據庫將數據表示成表的集合。表由數目已定的列和任意數目的行組成。每個數據庫都包括一組描述數據的邏輯和物理結構的系統目錄表,一個包含爲該數據庫分配的參數值的配置文件以及一個帶有正在進行的事務和可歸檔事務的恢復日誌。

1.1.3 節點組

節點組是一個或多個數據庫分區組成的集合。當您想爲數據庫創建表時,首先創建節點組以存儲表空間,然後創建表空間以存儲表。

1.1.4 表

關係數據庫將數據表示成表的集合。表由邏輯排列的行和列數據組成。所有數據庫的表數據都被存儲在表空間中。

1.1.5 視圖

視圖是高效率的數據呈現方法(無需維護數據)。視圖不是實際的表,不需要永久性存儲器。創建並使用一個“虛擬表”。

視圖可以包括它所基於的表中的所有或某些列或行。例如,可以在視圖中連接一個部門表和一個員工表,以便可以列出特定部門中的所有僱員。圖2顯示了表和視圖的關係。

1.1.6 索引

索引是一組關鍵字,其每一個都指向一些行。例如,圖3中,表A的一個索引基於表中的員工號碼。此關鍵字提供指向錶行的指針:員工號碼19指向員工KMP。通過使用指針創建指向數據的直接路徑,索引是更有效的存取錶行成爲可能。

SQL優化器自動選擇最有效率的存取表中數據的方法。當確定最快速的數據存取路徑時,優化器會將索引考慮在內。

可創建唯一索引以確保索引關鍵字的唯一性。索引關鍵字是定義了索引的一個列或一些列的有序集合。使用唯一索引將確保在編入的索引的列中,每個索引關鍵字的值都是唯一的。圖3顯示了索引與表之間的關係。

圖2. 表和視圖之間的關係

圖3. 索引與表之間的關係

1.1.7 模式

模式是一個標識符,如用戶ID,它幫助分組表和其他數據庫對象。模式可以歸個人擁有,擁有者可以控制對數據以及其中的對象的存取。

模式也可以是數據庫中的對象。它可以在創建模式中的第一個對象時自動創建。這樣的對象可以是任何可以由模式名限定的對象,如表、索引、視圖、程序包、單值類型、函數或觸發器。

1.1.8 系統目錄表

每個數據庫都包括一組描述數據的邏輯和物理結構的系統目錄表。DB2爲每個數據庫維護一大組系統目錄表。這些表包含有關數據庫對象(例如,用戶表、視圖和索引)的定義信息,以及用戶對這些對象所擁有的權限的安全性信息。它們在數據庫創建時被創建,並在常規操作期間得到更新。不能顯示的創建或卸載下它們,但是可以使用目錄視圖查詢和查看它們的內容。

1.2 存儲器對象

下列數據庫對象用來定義在系統上存儲數據的方式以及改進(與存取數據相關的)性能的方法:表空間、容器和緩衝池。

1.2.1 表空間

數據庫由稱爲表空間的部件組成。表空間是用來存儲表的位置。當創建表時,您可以決定將特定對象(如索引和大對象)數據與其餘表數據分開存放。表空間也可以分佈在一個或多個物理存儲設備上。圖4顯示了在表空間之間分佈數據時具有的一些靈活性。

圖4. 表空間

將容器分配給表空間。容器是分配的物理存儲器(如文件和設備)。

表空間可以使系統管理空間(SMS)或數據庫管理空間(DMS)。對於SMS表空間,每個容器都是操作系統的文件空間中的一個目錄,由操作系統的文件管理器控制存儲空間。對於DMS表空間,每個容器或者是固定大小的預分配文件,或者是物理設備如磁盤,由數據庫管理程序控制存儲空間。

表空間有三種類型:規則、臨時和長整數。

包含用戶數據的表存放在規則表空間中。缺省用戶表空間名爲USERSPACE1。索引也存儲在規則表空間中。系統目錄表存放在規則表空間中。缺省系統目錄表空間名爲SYSCATSAPCE。

包含長整數字段數據或長整數對象數據(如多媒體對象)的表存放在長整數表空間中。

臨時表空間分爲系統臨時表空間或用戶臨時表空間。系統臨時表空間用來存儲SQL操作(如排序、重組表、創建索引和連接表)期間所需的內部臨時數據。雖然可以創建任意數目個系統臨時表空間,但建議您只適用大多數表所使用的頁大小創建一個。缺省系統臨時表空間名爲TEMPSPACE1。用戶臨時表空間用來存儲已說明全局臨時表(已說明全局臨時表存儲的是應用程序臨時數據)。用戶臨時表空間不是在數據庫創建時缺省創建的。

1.2.2 容器

容器是物理存儲設備。它可以由目錄名、設備名或文件名標識。

將爲表空間分配容器。單個表空間可以橫跨多個容器,但每個容器只能屬於一個表空間。

圖5舉例說明了表與數據庫中的表空間、相關聯的容器和磁盤之間的關係。

圖5. 表空間、相關聯的容器和磁盤之間的關係

EMPLOYEE、DEPARTMENT和PROJECT表在HUMANRES表空間中,該表空間橫跨容器0、1、2、3和4。此示例顯示每個容器存在於不同的磁盤上。

任何表的數據都以循環方式存儲在表空間中的所有容器中。這能在屬於給定表空間容器之間平衡數據。數據庫管理程序在使用另一個容器之前寫入一個容器的頁數稱爲數據塊大小。

1.2.3 緩衝池

緩衝池指的是從磁盤讀去高速緩存表和索引數據頁時或修改它們時分配給它們的主存儲器。緩衝池的目的是改進系統性能。從內存存取數據要比從磁盤存取數據塊的多;因此,數據庫管理程序需要讀寫(I/O)的次數越少,性能也越好。(可以創建多個緩衝池,雖然在大多數情況下只需要一個。)

因爲可以縮短慢速I/O所造成的延遲,所以緩衝池的配置是最重要的調整項目。


2 表空間存儲

在存儲管理上,AIX系統採用邏輯卷管理策略。一個設備(邏輯卷)可以跨越多個磁盤,這就爲並行讀寫創造了可能。

目錄表空間和日誌表空間均存儲在文件系統中,而數據表空間的存儲類型通常是裸設備。一個表空間使用一個或多個設備(文件系統或裸設備)。

2.1 AIX系統存儲管理簡介

在AIX系統中,文件系統是建立在邏輯捲上的,邏輯卷是屬於一個卷組的,卷組是由實際的物理磁盤組成,邏輯卷在實際物理硬盤中可以不連續,它可以跨越多個物理硬盤而存在。AIX系統中物理與邏輯區段的映射如圖6所示

圖6. 物理到邏輯區段的映射

 

在邏輯上,邏輯卷存在於卷組中,而在物理上,它存在於物理捲上,物理卷是硬盤。硬盤的界面分爲5個同心區域:外邊緣(Outer-Edge)、外中間(Outer-Middle)、中央(Center)、內中間(Inner-Middle)和內邊緣(Inner-Edge),如圖7所示。

由於磁盤機械裝置的物理移動,邊緣(Edge)區域的搜索時間最長。邏輯卷位於哪個區域上,對於邏輯卷的讀寫效率影響很大。

其中,中央(Center)區域是磁盤搜索時間最短和訪問速度最快的。通常,把經常要訪問的邏輯卷放在磁盤的中央區域,把很少訪問的邏輯卷放在磁盤的邊緣(Edge)區域,其它邏輯卷放在磁盤的中間(Middle)區域。

圖7. 硬盤的分佈

2.2 裸設備和文件系統

數據庫的物理實現對數據庫的運行時性能至關重要,物理實現更多的需要考慮硬件和系統平臺。整合庫部署在一臺1900 MHz*4CPU,16GB內存的IBM小型機上,操作系統是IBM AIX 5.3,數據庫管理系統是DB2v9.1。

數據庫服務器的性能通常是通過事務吞吐量和應用程序響應時間來測量的,該性能主要取決於I/O子系統的性能。爲了獲得最大可能的I/O吞吐量,數據庫管理員和系統管理員需要特別注意數據庫表數據的佈局。在AIX系統中通常有兩種數據存儲形式:裸設備、文件系統。裸設備,也叫裸分區(原始分區),是一種沒有經過格式化,不被Unix通過文件系統來讀取的特殊字符設備。它由應用程序負責對它進行讀寫操作。不經過文件系統的緩衝。因爲使用裸設備避免了再經過AIX操作系統這一層,數據庫管理系統直接讀寫硬盤,所以使用裸設備對於讀寫頻繁的數據庫應用來說,可以極大地提高數據庫系統的性能。當然,這是以磁盤的I/O非常大,磁盤I/O已經成爲系統瓶頸的情況下才成立。如果磁盤讀寫確實非常頻繁,以至於磁盤讀寫成爲系統瓶頸的情況成立,那麼採用裸設備確實可以大大提高性能。

DB2數據庫有三種表空間:目錄表空間、數據表空間和日誌表空間。目錄表空間和日誌表空間均存儲在文件系統中,而數據表空間的存儲類型是基於實際情況和以往的開發經驗來決定。在我們的系統中,在ETL的任何一個階段都要求高速的磁盤I/O,尤其是數據抽取、匹配存儲過程和數據導入整合區存儲過程這三個過程,需要大批量的數據讀取或寫入,磁盤I/O是整合庫系統性能的瓶頸。根據經驗,數據表空間將採用裸設備的存儲方式。於是,整合庫的物理實現如下表所示。通常的系統可以採用這種模式。

邏輯結構

DB2表空間

邏輯設備/文件系統

空間大小

備註

目錄表空間

SYSCATSPACE

/db2_tag

3GB

文件系統

數據處理區

TBSPTEMP

/dev/rdb2tbsptemplv

/dev/rdb2tbsptemp2lv

10GB

10GB

裸設備

代碼對應區

TBSPINTE

/dev/rdb2tbspintelv

20GB

裸設備

整合區

日誌表空間

/intedb_log

20GB

文件系統

2.3 系統管理和數據庫管理

圖8. 表空間類型比較:系統管理和數據庫管理

 

2.4 如何合理創建表空間設備

2.4.1 原則

  1. 一個表空間跨多個物理磁盤,以獲得更好的I/O並行性
  2. 根據重要性不同,讓表空間分佈於磁盤的不同位置

ú         索引、重要數據位於中心

ú         將次重要數據、文件系統放在中間和邊緣

2.4.2 表空間容器的創建方法

按以下說明創建邏輯卷,並根據設備的重要性依次創建(首先創建最重要的),可以保證最重要的位於中央,按重要性依次往外排列,可以做到讀寫性能最優。

1.       smitlv

2.       選擇多個物理盤(PHYSICAL VOLUME names),界面如圖9所示。移動光標,用ESC+7選擇多塊物理磁盤PV。

圖9. 創建邏輯卷時選擇多個物理盤

3.       在Logical volume TYPE中輸入raw,即裸設備類型。

4.       物理盤區域(POSITION on physical volume)選擇center,將範圍(RANGE of physical volumes)選擇最大(maximum)。如圖10所示。

圖10. 使邏輯卷位於中央

2.4.3 整合數據庫表空間設備情況

整合數據庫在創建表空間設備時完全遵循了2.4.1節中的原則。

在創建邏輯卷時按照圖9所示創建,保證了一個設備跨越多個物理磁盤(儘可能多),以獲得更好的I/O並行性。

並且,嚴格按照重要性降低的次序作爲創建邏輯卷的順序。圖11顯示的是整合數據庫在磁盤hdiskpower8上的設備創建情況。由圖中看出,整合數據庫嚴格遵循了設備按照重要性分佈的原則:

ú        索引、重要數據位於中心

ú        將次重要數據、文件系統放在中間和邊緣

圖11. 設備按照重要性分佈

2.5 建庫語句參考

綜合查詢系統數據庫部分建庫語句:

---創建數據庫在一個2G的文件系統/anly_tag

db2 create database anly on /anly_tag alias anly using codeset gbk territory cn collate using system

 

---創建bufferpool

db2 connect to anly user db2admin

db2 create bufferpool TMPBF32K immediate size 32000 pagesize 32k

 

---創建數據表空間(8G*4)並指定相應的bufferpool

db2 create tablespace TBSPANLY pagesize 32 k managed by database using (device '/dev/ranlytbsplv' 262144) bufferpool TMPBF32K

db2 alter tablespace TBSPANLY add(device '/dev/ranlytbsplv2' 262144)

db2 alter tablespace TBSPANLY add(device '/dev/ranlytbsplv3' 262144)

db2 alter tablespace TBSPANLY add(device '/dev/ranlytbsplv4' 262144)

 

---創建系統臨時表空間(2G的文件系統/anly_tmp/tmp)並指定相應的bufferpool

db2 create system temporary tablespace TBSPTMP32K pagesize 32k managed by system using ('/anly_tmp/tmp') extentsize 8 prefetchsize 16 bufferpool TMPBF32K

 

----修改日誌文件大小爲25000*4K

db2 update db cfg for anly using LOGFILSIZ 25000

db2 update db cfg for anly using LOGPRIMARY 20

db2 update db cfg for anly using LOGSECOND 50

db2 update db cfg for anly using NEWLOGPATH /anly_log

 

----修改表空間大小

db2 alter tablespace tbsptemp drop (device '/dev/rdb2tbsptemp2lv')

db2 alter tablespace tbsptemp resize (device '/dev/rdb2tbsptemp3lv' 327680)

 


3 緩衝池和表空間

3.1 緩衝池

通常,爲每一頁面大小的系統臨時表空間建立一個緩衝池就足夠了。因爲在緩衝池管理方面,我們完全可以信任DB2。如果想在這方面繼續提高性能,則可以參考本節的文字。

DB2在其緩衝池的自我調優方面十分擅長,並且會將經常被訪問的行放入內存,因此一個緩衝池就足夠了。(這一選擇也避免了管理多個緩衝池的複雜性。)

如果時間允許,並且需要進行改進,那麼可能需要使用多個緩衝池。其思想是將訪問最頻繁的行放入一個緩衝池中。在那些隨機訪問或者很少訪問的表之間共享一個緩衝池可能會給緩衝池帶來“污染”,因爲有時候要爲一個本來可能不會再去訪問的行消耗空間,甚至可能將經常訪問的行擠出到磁盤上。如果將索引保留在它們自己的緩衝池中,那麼在索引使用頻繁的時候(例如,索引掃描)還可以顯著地提高性能。

這與我們對錶空間的討論是緊密聯繫的,因爲要根據表空間中表的行爲來分配緩衝池。如果採用多緩衝池的方法,採用4個緩衝池比較合適:

1.         一箇中等大小的緩衝池,用於臨時表空間。

2.         一個大型的緩衝池,用於索引表空間。

3.         一個大型的緩衝池,用於那些包含經常要訪問的表的表空間。

4.         一個小型的緩衝池,用於那些包含訪問不多的表、隨機訪問的表或順序訪問的表的表空間。

3.2 緩衝池大小

緩衝池大小需要綜合考慮系統內存和服務器工作負載情況而定。通常,OLTP類型分配75%的可用內存;OLAP類型分配50%的可用內存,將剩下的50%分配給SORTHEAP。

緩衝池對應於系統的內存空間,所以千萬不要爲緩衝池分配多於所能提供的內存,否則就會招致代價不菲的OS內存分頁。通常來講,如果沒有進行監控,要想知道一開始爲每個緩衝池分配多少內存是十分困難的。對於OLTP類型的工作負載,一開始將75%的可用內存分配給緩衝池比較合適。對於OLAP/DSS,經驗法則告訴我們,應該將50%的可用內存分配給一個緩衝池(假設只有一種頁面大小),而將剩下的50%分配給SORTHEAP。

3.3 表空間頁大小

在頁大小足以容納一條記錄的前提下,隨機更新操作,傾向於用較小的頁大小;而對於一次訪問大量行的操作,較大的頁大小可以提供更好的性能。

爲了創建一個表,必須有一個表空間,其頁面大小應足以容納一行。您可以選擇使用 4、8、16或32KB這幾種頁面大小。有時候必須使用較大的頁面大小,以迴避某些數據庫管理器的限制。例如,表空間的最大尺寸與表空間的頁面大小成比例。如果使用4K的頁面大小,那麼表空間的大小(每個分區)最大是64GB,如果使用32K的頁面大小,那麼最大是512GB。

對於執行隨機更新操作的OLTP應用程序,採用較小的頁面大小更爲可取,因爲這樣消耗的緩衝池中的空間更少。

對於要一次訪問大量連續行的OLAP應用程序,通常使用較大頁面大小效果會更好些,因爲這樣可以減少在讀取特定數量的行時發出的I/O請求的數量。較大的頁面大小還允許您減少索引中的層數,因爲在一頁中可以保留更多的行指針。然而,也有例外情況。如果行長度小於頁面大小的255分之1,則每一頁中都將存在浪費的空間,因爲每頁最多只能有255行(對於索引數據頁不適用)。在這種情況下,採用較小的頁面大小或許更合適一些。

3.4 系統臨時表空間

爲每種頁面大小的表空間,建立一個系統臨時表空間,通常使用文件系統,大小根據排序和重組事物的大小確定。

對於所使用的每種頁面大小,必須存在一個具有匹配頁面大小的系統臨時表空間(以支持排序和重組)。然後將所有享用匹配頁面大小的表空間指派給具有相同頁面大小的緩衝池。

如果對性能還有更苛刻的要求,並且有時間投入,那麼可以使用DMS表空間,並且根據使用情況來組織表。另外,還要遵循前面給出的關於使用多個緩衝池的建議。對於每種頁面大小,創建一個:

1.         系統臨時表空間。

2.         用於索引的常規表空間。

3.         用於頻繁訪問的表的常規表空間。

4.         用於訪問不多的表、隨機訪問的表以及順序訪問的表的常規表空間。

5.         用於 LOB 數據的大型表空間。

3.5 區段大小和預取大小

區段大小(extent size)和預取大小(prefetch size)是表空間的參數,對於數據存取性能至關重要。

區段大小跟表空間中表的平均大小有一定的比例關係,通常表越大,區段大小也越大。如果表空間駐留在磁盤陣列上,則區段大小應設置成條紋大小。

預取大小通過公式確定:prefetch size = (#containers of the table space on different physical disks) * extent size。

磁盤陣列的情況:prefetch size = extentsize * (# of non-parity disks in array)。

3.5.1 區段大小

extent size指定在跳到下一個容器之前,可以寫入到一個容器中的PAGESIZE頁面的數量,這個參數是在創建表空間時定義的(之後不能輕易修改)。處理較小的表時,使用較小的區段效率會更高一些。

下面的經驗法則是建立在表空間中每個表的平均大小的基礎上的:

1.         如果小於25MB,extent size爲8

2.         如果介於25到250MB之間,則extent size爲16

3.         如果介於250MB到2GB之間,則extent size爲32

4.         如果大於2GB,則extent size爲64

對於OLAP數據庫和大部分都要掃描(僅限於查詢)的表,或者增長速度很快的表,應使用較大的值。

如果表空間駐留在一個磁盤陣列上,則應將區段大小設置成條紋大小(也就是說,寫入到陣列中一個磁盤上的數據)。

3.5.2 預取大小

對於預取大小,可以通過使用ALTERTABLESPACE輕易地修改。最優設置差不多是這樣的:prefetch size = (# containers of the tablespace on different physical disks) * extent size。

如果表空間駐留在一個磁盤陣列上,則設置如下:prefetch size = extent size * (# of non-parity disksin array)。


4 提高SQL語句執行效率

4.1 建立索引

使用索引實現關鍵數據的高效訪問。但是需要知道每個索引都會給數據庫更新帶來額外的開銷。這就意味着,低效的索引會給數據庫帶來災難。

對於數據庫,我們必須關注關鍵數據的讀取,爲他們提供最高效的訪問路徑。對此,基本策略就是建立索引。在索引提供高效訪問的同時,也帶來了額外的系統開銷。開銷分爲磁盤空間的開銷和處理器開銷。下面我們討論一下處理器開銷。每當在表中插入或刪除記錄時,該表的所有索引必須進行相應調整。每當對已建立索引的字段進行更新時,這種調整也會發生。舉例子說,如果在未建立索引的表中插入數據需要100個單位時間,那麼每增加一個索引就會增加100到250個單位時間。有趣的是,維護索引的開銷與簡單觸發器帶來的開銷大致相當。

在建立索引前線介紹一些最通俗的信息,這些信息來自developWorks,列出這些信息是因爲我覺得這些信息通常情況下是值得參考的:

1.         當要在一個合理的時間內結束查詢時,應避免添加索引,因爲索引會降慢更新操作的速度並消耗額外的空間。有時候還可能存在覆蓋好幾個查詢的大型索引。

2.         基數較大的列很適合用來做索引。

3.         考慮到管理上的開銷,應避免在索引中使用多於5個的列。

4.         對於多列索引,將查詢中引用最多的列放在定義的前面。

5.         避免添加與已有的索引相似的索引。因爲這樣會給優化器帶來更多的工作,並且會降慢更新操作的速度。相反,我們應該修改已有的索引,使其包含附加的列。例如,假設在一個表的 (c1,c2)上有一個索引i1。您注意到查詢中使用了"wherec2=?",於是又創建一個(c2)上的索引i2。但是這個相似的索引沒有添加任何東西,它只是i1的冗餘,而現在反而成了額外的開銷。

6.         如果表是隻讀的,並且包含很多的行,那麼可以嘗試定義一個索引,通過CREATE INDEX中的INCLUDE子句使該索引包含查詢中引用的所有列(被INCLUDE子句包含的列並不是索引的一部分,而只是作爲索引頁的一部分來存儲,以避免附加的數據FETCHES)。

對於數據倉庫(查詢系統數據庫)可以建立較多的索引(索引和數據的比例可以是1:1)。

決定是否使用索引,可以重點考慮檢索比率。即,判斷索引有效性的依據,就使用鍵值作唯一性條件檢索出的數據的百分比。百分比越低,索引越有效。做出這個論斷的前提是一些假設,如磁盤訪問的相關性能。

索引鍵值相關記錄的物理位置是否相鄰也很重要,因爲是通過塊來操作數據的。建立了索引之後,如果索引鍵所指向的記錄散佈於整個表中,即使這些記錄在表中佔的比率很小,但因爲它們分散在整個磁盤上,所以索引的性能就會大打折扣。

另外值得注意的是,函數和類型轉換可能導致索引失效。

4.2 採用表分區

DB2 V9新增了表分區功能,分區技術可以改進大型數據庫的管理。

每個表分區物理獨立。

分區鍵的選擇:讓查詢很快定位,但儘量避免數據庫操作集中;使海量數據表拆分成“小表”,並使數據庫操作平均分散到表分區中。

分區在單節點數據庫上,提高查詢定位的速度,不提供查詢並行性。

DB2 V9新增了表分區功能,分區技術可以改進大型數據庫的管理。DB2 V9新增了表分區功能,因此對一些大表,我們在DB2 V9中不再需要分拆成小表,再用UNION ALL視圖的方式進行設計,而是直接用分區表實現一些這些功能。表分區功能是一種數據組織方案,即,表數據根據一個或多個表列中的值分佈到多個存儲對象(稱爲數據分區或範圍)中。每個數據分區都是單獨存儲的。這些存儲對象可以在不同的表空間中,也可以在相同表空間中。

很多業務數據的查詢包含時間條件,所以時間經常作爲分區條件。業務數據在時間上的分佈通常是平均的,所以用時間分區的另一個好處是使包含大型數據的表分成大小相當的幾個分區,用戶還可以針對數據量來制定分區,以控制每個分區的數據量在一個可以接受的範圍內。在外匯管理局統計分析子系統中,用戶的每一次查詢均包含時間條件,所以按時間分區是一個很好的選擇。外匯局國際收支數據明細表每年有2000萬數據,使用時間一長,數據量將非常之大。明細數據按月分區,可以將每個分區的數據量控制在200萬左右,在查詢時控制時間條件在一年內,這樣可以避免查詢時全表掃描帶來的壓力。

但是按照時間分區也有弊端。一個業務系統,按時間按分區,當前時間下的分區插入、刪除、更新或查詢的操作必定比別的分區多。這種集中的操作必定給數據庫帶來巨大的壓力。

外匯管理局統計分析子系統還有另外一個特點:用戶按照行政區劃分散,查詢時只關心所在行政區劃的數據。我們就有一種構想:可否按照時間和行政區劃兩個條件來分區(按月、按省分區)?這一想法剛剛產生,還未執行,接下來打算測試。

分區鍵的選擇:讓查詢很快定位,但儘量避免數據庫操作集中;使海量數據表拆分成小表,並使數據庫操作平均分散到表分區中。

對於分區,我們進行了一些列測試,下面就是我們測試的結論。分區在單節點數據庫上,提高查詢定位的速度,不提供查詢並行性。以一年的數據量,月分區爲例。首先,考慮查詢條件中有分區字段時的情況。當查詢條件在一個月內時,DBMS可以直接定位到某個分區,在不考慮其他條件時,查詢速度是不分區表的12倍。依此類推,當查詢條件跨N(N<=12)個月時,查詢速度是不分區表的12/N倍。如果,查詢條件中沒有分區字段時,分區和不分區查詢效率相當。

4.3 運行統計和重組

優化器需要知道索引的相關信息,來判斷查詢執行的“路徑”,運行統計可以告訴優化器。經驗:當表中數據量變化達到10%時,需要重新運行統計。

在許多次的更新之後,表會成爲碎片狀,這導致性能嚴重下降。若收集了統計信息,但看不出有明顯的性能改進,則重組表數據可能會有幫助。重組表數據時,根據指定的索引重新安排數據的物理順序,併除去碎片數據中的空閒空間。這使該數據可以更快速的被存取,從而改進性能。

4.3.1 通過運行統計來收集索引信息

運行統計(runstats)的作用是收集索引的統計信息,如果數據庫沒有收集索引的統計信息,優化器就無從下手,只能按部就班,通過全表掃描來執行查詢。所以,新創建的索引需要重新運行統計,否則索引無效。

舉一個例子,有個表TABLE1,其中有一個字段COL1取值是“1”、“2”、“3”三種,運行統計的結果是告訴數據庫TABLE1中的數據其中字段COL1的各種取值所佔的比重。示意如下:

“1” -12%;

“2” - 66%;

“3” - 22%。

假設還有個字段COL2取值和數據所佔的百分比如下:

“A” - 50%;

“B” - 50%。

則查詢語句1:

select * from TABLE1 where COL1 = “1” and COL2 = “A”,

數據庫優化器會優先選擇字段COL1上的索引來定位表中的數據,因爲通過COL1上的索引就可以將結果集迅速定位在一個小範圍內12%。而相反的,對於查詢語句2:

select * from TABLE1 where COL1 = “2” and COL2 = “A”,

數據庫會優先選擇COL2上的索引,因爲對於語句2的查詢條件COL2上的索引具有更好的區分度。

從上面可以看出,數據庫的優化器通常會優先選擇區分度較高的索引(針對於查詢條件,條件不同選擇的索引可能不同)。

數據庫裏的數據是變化的,所以某個時候採集的統計信息,過一段時間後可能會過時,甚至誤導DB2優化器,這樣同樣會造成運行性能的低下。所以除了,最初建立索引時需要運行統計,在表中的數據發生變化時也需要運行統計。經驗:當表中數據量變化達到10%時,需要重新運行統計。

4.3.2 存儲過程裏執行運行統計語句

運行統計的語句如下:runstats on table DB2ADMIN.TABLE withdistribution and detailed indexes all;

在存儲過程中不能直接執行runstats語句,可以通過調用ysproc.admin_cmd來實現,具體語句如下:

callsysproc.admin_cmd('runstats語句');

下面用一個存儲過程封裝了此過程,在需要對一個表運行統計時,只需要調用pr_runstats存儲過程即可。

/****************************************************************

* Name: pr_runstats

 * Description: 運行統計表

 * Creator: 趙堅密

 * Creation date: 2008-12-30

 * Parameters: str

* ---------------------------------------------

 * db2 connect to inte user db2admin using db2admin

 *編譯過程

 *db2 -td@ -vf pr_runstats.db2

 *運行過程

 *db2 call pr_runstats()

 ***************************************************************/

drop procedure pr_runstats(varchar(100))@

create procedure pr_runstats(IN_TABLE_NAME varchar(100))

language sql

begin

    declare rowcount integer default 1;

    declare errLog  varchar(400);

    declare sqlcode integer ;

    declare sqlstate char(5) ;

    declare str_sql varchar(150);

    declare not_found CONDITION FOR SQLSTATE '02000';

    declare CONTINUE HANDLER FOR not_found

        set rowcount = 0;

    declare exit handler for sqlexception

        call pr_log('truncat_table', errLog, sqlcode, sqlstate);

    call pr_log('truncat_table', '運行統計'||IN_TABLE_NAME, 0, '0');

    call sysproc.admin_cmd('runstats on table DB2INST1.'||IN_TABLE_NAME||' with distribution and detailed indexes all');

    call pr_log('truncat_table', '運行統計'||IN_TABLE_NAME, 0, '0');

    commit;

end@

4.3.3 重組表中的數據

重組(reorg)操作會重新排列表數據的物理順序,併除去碎片數據中的空閒空間。

由於刪除操作不釋放磁盤空間,在執行刪除操作後,表會成爲碎片狀,這導致性能嚴重下降,在多次更新操作之後也會出現這種情況。若收集了統計信息,但看不出有明顯的性能改進,則重組表數據可能會有幫助。重組表數據時,根據指定的索引重新安排數據的物理順序,併除去碎片數據中的空閒空間。這使該數據可以更快速的被存取,從而改進性能。

4.4 減少對數據庫的更新和刪除操作

刪除和更新操作的開銷往往比插入高,所以一個好的設計需要減少對數據庫的更新和刪除操作。

4.4.1 更新操作

數據庫的更新操作會帶來一連串的“效應”:更新操作需要記錄日誌(以便錯誤時回滾);更新可變長字段(如,varchar類型)會帶來數據物理存儲的變化(記錄的移動);更新索引字段會導致索引重建;更新主鍵會導致數據重組等。這一切不但會造成更新操作本身效率低,而且由於磁片碎片的產生會造成以後查詢性能的降低。爲了應對這一情況,有兩種策略:一、減少更新次數,把多個字段的更新寫到同一個語句裏;二、避免更新。這兩種策略分別適用於不同的情況,下面將舉例說明兩種情況。

4.4.1.1減少更新次數

在整合庫裏有個代碼清洗過程,就是通過連接代碼表給業務數據的自編碼字段賦值。代碼清洗其實是通過關聯代碼表來更新業務數據表的一個過程,需要連接多個代碼表,更新多個自編碼字段。完成此更新,有兩種更新語句的寫法:一種是寫成多個SQL語句,每個語句更新一個自編碼字段;另一種寫法是將所有更新寫在一個語句中。更新銀行代碼的更新語句如下所示:

updateTBL_INCOME_TMP A

setBANKCODESELF = (

    select SELFCODE

    from

        TBL_BANKINFO B

    where A.BANKCODE = B.BANKCODE )

通過一個更新語句實現多個自編碼字段更新的語句示意如下:

updateTBL_INCOME_TMP

set 代碼1自編碼 = 通過關聯代碼1表得到自編碼,

    代碼2自編碼 =通過關聯代碼2表得到自編碼,

    ...,

    代碼n自編碼 =通過關聯代碼n表得到自編碼

利用兩千萬的測試數據。兩種方法的測試結果如下表所示。從測試結果看出,一次更新方法性能提高了十倍,大大提高了性能。

處理過程

多次更新方法耗時

一次更新方法耗時

代碼清洗

0:29:48

0:02:59

4.4.1.2避免更新

下面舉個通俗的例子,這類情況是經常遇到的。某公司有一套系統員工考勤系統,爲了提高查詢統計的性能,在原有系統基礎上建立了一些包含冗餘信息的表。以員工表爲例,它獲得數據的過程如圖12所示。第一步把員工信息放到新表中,然後連接通過字段“部門ID”連接更新“部門名稱”。

圖12. 關聯更新

一般,爲了節省存儲開支把部門名稱這樣的字段設計成可變長的。所以在對它進行更新時會造成磁盤數據的重新組織,形成磁盤碎片,影響查詢性能。

爲了避免這樣的情況發生,我們可以使用如圖13所示的方法避免更新。這種方法一步完成了冗餘數據表的插入,再插入時連接部門表獲得“部門名稱”,從而避免了更新操作。

圖13. 避免更新

4.4.2刪除操作

初學者可能認爲刪除操作很簡單,可以快速完成。其實這是一個錯誤的理解,刪除過程需要大量掃描磁盤;需要記錄數據庫日誌;而且刪除過程不釋放磁盤空間,浪費磁盤,並且使磁盤上的數據支離破碎,這對後續查詢的性能是一個致命的打擊。通常用兩種方式來應對:一、對經常做刪除操作的表進行重組(reorg);二、避免刪除。

4.4.2.1重組

見4.3.3節。

4.4.2.2避免刪除——中間表和正式表模式

在數據需要比較複雜的處理的時候經常會用到中間表和正式表模式。數據在中間表中被處理,然後把滿足條件的數據轉移至正式表,不滿足條件的數據保留在中間表中。圖14示意了數據從中間錶轉移到正式表的過程:在完成數據處理之後,需要把中間表temp1flag = 1的數據插入到正式表,並刪除中間表temp1flag = 1的數據。

圖14. 從中間表向正式錶轉移數據

因爲flag字段不是聚簇索引,所以當對中間表temp1進行刪除後,會再磁盤中留下大量碎片,如圖15所示。不但會留下那麼多的磁盤碎片,而且已刪除的數據的空間也不會自動釋放。結果是不但浪費磁盤空間,而且查詢性能會急劇下降。

圖15. 刪除操作後的磁盤碎片

咱們可以使用清空表的命令來避免刪除操作。除了中間表temp1和正式表,添加輔助臨時表temp2。如果temp1中保留的數據flag=0只佔有10%,這一優化將顯著提升性能。具體步驟如下:

1.         將temp1flag=0的數據,插入到temp2

2.         清空表temp1

alter table temp1 ACTIVATE NOT LOGGED INITIALLY WITH EMPTY TABLE ;

3.        將temp2中的數據插入temp1

4.4.2.3存儲過程裏實現表清空

在存儲過程裏不能直接執行表清空語句來清空表,但是可以通過以下命令來實現:

EXECUTE IMMEDIATE str_sql;   (其中str_sql,爲sql語句)

下面用一個存儲過程封裝了此過程,在需要對一個表運行清空時,只需要調用pr_truncat_table存儲過程即可。

/****************************************************************

* Name: pr_truncat_table

 * Description: 將一個表初始化成空表(刪除所有記錄),不記日誌

 * Creator: 趙堅密

 * Creation date: 2008-1-2

 * Parameters: str

 * ---------------------------------------------

 * db2 connect to inte user db2admin using db2admin

 *編譯過程

 *db2 -td@ -vf income_to0206.db2

 *運行過程

 *db2 call pr_truncat_table()

***************************************************************/

drop procedure pr_truncat_table(varchar(100))@

 

create procedure pr_truncat_table(IN_TABLE_NAME varchar(100))

language sql

begin

    declare rowcount integer default 1;

    declare errLog  varchar(400);

    declare sqlcode integer ;

    declare sqlstate char(5) ;

    declare str_sql varchar(150);

    declare not_found CONDITION FOR SQLSTATE '02000';

    declare CONTINUE HANDLER FOR not_found

        set rowcount = 0;

    declare exit handler for sqlexception

        call logNote('truncat_table', errLog, sqlcode, sqlstate);

      

    call logNote('truncat_table', '清空表'||IN_TABLE_NAME||'中的記錄', 0, '0');

    set str_sql = 'alter table '||IN_TABLE_NAME||' activate not logged initially with empty table';

    EXECUTE IMMEDIATE str_sql;

    call logNote('truncat_table', '清空表'||IN_TABLE_NAME||'中的記錄完成', 0, '0');

    commit;

end@

4.5 如何使訪問更高效

本小節的內容很大一部分來自《TheArt of SQL》這本書,這本書裏集合了數據庫開發的通用經驗。雖然沒有侷限於具體的DBMS和硬件平臺,但是卻是一本實踐性很強的書。

1.一次連接數據庫,做很多事情。直到處理完,才斷開連接。

2.一個SQL語句包含儘量多的操作。形象地說:幾千個語句,藉助遊標不斷循環,很慢。換成幾個語句,處理同樣的數據,還是很慢。換成一個語句,解決問題,最好。

3.接近DBMS核心。儘量使用數據庫自帶的函數。減少自定義函數。因爲再聰明的數據庫優化器也不認識自定義函數。

4.一個語句不要連接太多的表,建議的上限是5個。

5.將頻繁更新的列集中起來:當更新某一行時,DB2 會記錄進行更改的所有列,因此將頻繁更新的列放到一起可以減少 DB2 的記錄工作。這只是一個有關性能的小建議,因此不應爲實現它而進行重大的應用程序或數據庫設計修改。

6.如果想了解,如何書寫SQL語句才能更高效,可參考《TheArt of SQL》。書中提出了不少有益的見解。


5 參數調優

關於數據庫服務器的參數調優包括,操作系統參數、數據庫管理系統參數和數據庫參數的調優。其中操作系統調優的核心在於AIX系統的內存和CPU的調優,旨在提高數據庫對內存和CPU的利用率。DB2數據庫的調優分爲3個方面:DB2環境變量、DB2實例參數和數據庫參數。旨在提高數據庫的並行性、讀寫性能、排序和彙總性能。

參數設置和參數調優通常根據經驗確定,以下小節介紹的是整合庫的參數設置。如想了解綜合查詢系統數據庫,可參看《查詢庫性能調優》的參數調優部分。

5.1 AIX系統

vmo -o maxclient%=20

vmo -o maxperm%=20

vmo -o minperm%=5

這三個參數是AIX內存管理相關的。下面介紹這三個參數。

增強JFS文件系統爲它的緩衝區高速緩存使用客戶機文件。爲了在增強JFS文件系統的高速緩存中建立硬性限制,可以調諧maxclient的參數。該參數代表了可用於緩衝區高速緩存的客戶機頁面的最大值。可以使用vmo -o maxclient命令進行更改。maxclient的值顯示爲實內存的百分比。

在到達maxclient閾值後,LRU開始取用最近尚未訪問過的客戶機頁面。如果沒有足夠的客戶機頁面可以被竊取,LRU會替換掉其它類型的頁。通過減少maxclient的值,可以阻止增強JFS文件頁的訪問不要替換掉工作存儲頁面,最小化調頁空間的頁面調度。另外,maxclient通常應該設置爲一個小於或等於maxperm的值。

操作系統通過把在曾經讀寫的內存頁留在實內存滿足不同要求。如果文件頁面在它們的頁幀被重新分配前被請求,那就節省了輸入輸出操作。

頁幀使用的文件相對用於計算的(工作或程序文本)段的文件的比例是鬆散地受控於minperm和maxperm的值的:

如果RAM中文件頁面所佔的百分比高於maxperm,頁面替換的竊取只用於文件頁。

如果RAM中文件頁面所佔的百分比低於minperm,頁面替換的竊取同時用於文件頁和計算頁。

如果RAM中文件頁面所佔的百分比介於minperm和maxperm之間,頁面替換隻竊取文件頁,除非文件頁的重調入數量大於計算頁數。

5.2 DB2環境變量

db2set DB2_PINNED_BP=YES

db2set DB2_FORCE_FCM_BP=NO

db2set DB2MEMMAXFREE=1048576

db2set DB2_MMAP_WRITE=NO

db2set DB2_MMAP_READ=NO

db2set DB2_HASH_JOIN=Y

db2set DB2_RR_TO_RS=ON

慎用,請詳細瞭解後再使用以下參數:

DB2_EVALUNCOMMITTED=YES

DB2_SKIPDELETED=ON

DB2_SKIPINSERTED=ON

DB2_PARALLEL_IO=YES

DB2_PINNED_BP:這個AIX和HP-UNIX平臺上的變量指定是否數據庫使用的全局內存(包括緩衝池的內存)將被保留在系統主存儲器以獲得更加穩定的數據庫性能。

DB2MEMMAXFREE:該變量指定每個DB2代理將保留可以用內存的數量;取值範圍從0到2.0e+32字節。缺省是8,388,608個字節。

DB2_HASH_JOIN:指定排序時使用HASH排序,這樣db2在表join時,先對各表做hash排序,再join,這樣可以大大提高性能。

DB2_RR_TO_RS:該設置後,不能定義RR隔離級別,如果定義RR,db2也會自動降爲RS。通過不鎖定插入或者更新行的下一個鍵,可以改進併發性,提高性能。

DB2_EVALUNCOMMITTED:這個參數將在記錄鎖之前進行謂詞檢查,儘量減少鎖的時間。對於V8,從V8.1 FP9(也即V8.2 FP2)開始,最佳的設置是=YES_DEFERISCANFETCH。對於 V9,只需指定=YES。

DB2_SKIPDELETED:這個參數將新insert且沒有提交的數據跳過;例如,SELECT/UPDATE語句不會發現這條記錄。

DB2_SKIPINSERTED:這個參數將新delete且沒有提交的數據跳過;例如,SELECT/UPDATE語句不等待這條記錄的提交,並且認爲他已經被刪除了。

DB2_PARALLEL_IO:允許表空間的並行I/O。

5.3 DB2數據庫實例參數

db2 update dbm cfg using FEDERATED YES

db2 update dbm cfg using sheapthres 200000

db2 update dbm cfg using ASLHEAPSZ 120

db2 update dbm cfg using MAXAGENTS 200(連接進程數)

db2 update dbm cfg using NUM_POOLAGENTS 30

FEDERATED:數據庫聯邦。

sheapthres:排序堆閾值。

ASLHEAPSZ:

MAXAGENTS:指定可在任何給定時間接受應用程序請求的數據庫管理器代理進程的最大數目。

NUM_POOLAGENTS:確定空閒代理進程池的最大大小。

5.4 DB2數據庫參數

db2 update db cfg for database_name using PCKCACHESZ 2048

db2 update db cfg for database_name using SORTHEAP 10000(排序堆大小)

db2 update db cfg for database_name using APPLHEAPSZ 4096

db2 update db cfg for database_name using MAXLOCKS 30

db2 update db cfg for database_name using DFT_DEGREE 4

db2 update db cfg for database_name using DBHEAP 8192

db2 update db cfg for database_name using LOGBUFSZ 256

db2 update db cfg for database_name using DFT_PREFETCH_SZ 64

db2 update db cfg for database_name using LOCKLIST 5000

db2 update db cfg for database_name using NUM_IOCLEANERS 5

 


6 開始行動

6.1 用topas監控硬件使用情況

在IBM AIX操作系統中,可以用topas命令來監控CPU、硬盤、內存、網絡等硬件使用率和使用情況。總結幾點:

1.         執行數據庫操作時,少量硬盤的使用率達到百分之百,大量硬盤處於空閒,並有讀寫等待現象。說明磁盤的並行性不好,需要通過合理分配磁盤來優化。

2.         少量CPU使用率達到百分之百,大量CPU處於空閒。說明應用的並行度不夠高。

3.        CPU大量處於I/O等待,是不理想的狀態,需要優化磁盤I/O。

6.2 從執行時間來確定主要矛盾

這裏的執行時間可以是一個DB2執行一個SQL語句的時間,也可以是一個存儲過程的時間。

從執行時間來定位最需要優化的部分,是一個很好的選擇。因爲,執行時間長的過程(指SQL語句、存儲過程等),通常意味着優化後效果更明顯。試想,有兩個過程,分別執行這兩個過程,一個用了一個小時,一個用了十分鐘。我們試圖優化這兩個過程,通過相同的努力使兩個過程性能都提高了10%。這樣,第一個過程執行時間縮短了6分鐘,第二個過程縮短了1分鐘。可以看出,付出相同努力的情況下第一個過程收效是第二個過程的6倍。所以,我們優先優化執行時間長的過程,如果需要進一步優化,再去優化那些執行時間較短,還有優化餘地的過程。

DB2沒有較好的統計執行時間的可視化工具,所以,用戶通常需要自己來實現並記錄各個過程的執行時間。下面介紹一種“土方法”。在數據庫裏創建一個日誌表,建表語句如下:

create table TBL_PRO_LOG

(

   ID                     INTEGER,

   PRO_NAME            CHAR(50),

   DESCRIPTION          VARCHAR(255),

   PRO_TIME             TIMESTAMP,

   SQL_CODE             INTEGER,

   SQL_STATE            VARCHAR(200),

   constraint P_Key_1 primary key (ID)

);

同時創建一個記錄日誌的存儲過程,用戶需要時可以通過調用此存儲過程來記錄被監控過程的起始時間、完成時間和錯誤日誌等。通過查看日誌表,就可以統計過程執行的時間。在異常時調用此存儲過程,可以掌握系統出錯信息,能更好的定位錯誤,便於錯誤處理。

/****************************************************************

* Name: logNote

 * Description: 輸出日誌,大多在其他存儲過程中調用,往TBL_PRO_LOG裏insert列。

 * Creator: 陳偉

 * Creation date: 2007-10-22

 * Parameters:description,sCode,sState

 * Input:description,sCode,sState             Output:TBL_PRO_LOG

 * ---------------------------------------------

 * db2 connect to inte user db2admin using db2admin

 *編譯過程

 *db2 -td@ -vf logNote.db2

 *運行過程

 *db2 call logNote()

 * -------------------------------------------------------------

***************************************************************/

 

drop procedure logNote(CHAR(50),VARCHAR(255),INTEGER,CHAR(5))@

create procedure logNote(tblname char(50),description VARCHAR(255),sCode INTEGER,sState CHAR(5))

language sql

begin

    insert into TBL_PRO_LOG(description,tbl_name ,Pro_Time, sql_code, sql_state)

    values(description, tblname,current timestamp, sCode, sState);

    commit;

end@

通過以上方法,咱們就可以統計各個過程的執行時間,並且可以挑選出執行時間較長的過程來作爲優化的“重點關注對象”,而進入觀察階段。

6.3 進一步觀察以決策

上一節確定了一些“重點關注”的過程,用來作爲觀察的對象,以作出是否需要優化這一決斷。本節將介紹DB2的幾種工具,用來查看SQL語句的執行情況。

6.3.1 DB2Visual Explain

DB2提供了非常直觀有效的方法來查看查詢的存取計劃。DB2 Visual Explain能夠獲得可視化的查詢計劃,而DB2expln命令則可以獲得文本形式的查詢計劃。有了查詢計劃,我們就可以有針對的對查詢進行優化。根據查詢計劃找出代價最高的掃描(表掃描,索引掃描等)和操作(Join,Filter,Fetch等),繼而通過改寫查詢或者創建索引消除代價較高的掃描或操作來優化查詢。

DB2提供了多種方法來得到可視化查詢計劃。

通過DB2Control Center獲得可視化查詢計劃。如圖12:

圖12. 可視化查詢計劃

點擊“ExplainSQL”後輸入要進行分析的查詢語句以及查詢標號和標籤,點擊Ok按鈕便可得到可視化的查詢計劃。此時,查詢計劃會被存儲在系統的Explain表中。用戶可以通過圖12中的“Show Explained Statements History”命令獲得存儲在Explain表中的所有查詢計劃。

通過CommandEditor(在DB2 8.2版本之前叫做CommandCenter)獲得可視化的查詢計劃。如圖13:

圖13. 獲得可視化的查詢計劃

在主窗口輸入查詢並連接數據庫後,點擊圖中所示的按鈕即可得到可視化的查詢計劃,如圖14:

圖14. 查詢計劃結果

在圖14所示的查詢計劃中,還可以點擊圖示中的每個節點來察看詳細的統計信息。譬如雙擊節點:“FETCH(13) 21,959.75”後將會彈出如圖15所示的對話框:

圖15. 詳細的統計信息

圖15中的統計信息主要包括此FETCH操作的總代價、CPU、I/O以及獲得結果集中的第一行的代價。在這裏,timerons是結合了CPU和I/O代價的成本單位。此外,圖15中還收集了其他相關信息。譬如此操作讀取了哪個表的哪些列,每個謂詞的選擇度(selectivity),使用了多少buffer等等。

6.3.2 DB2exfmt

DB2exfmt命令能夠將Explain表中存儲的存取計劃信息以文本的形式進行格式化輸出。DB2exfmt命令將各項信息更爲直觀的顯示,使用起來更加方便。命令如下:

DB2exfmt -d <db_name> -e <schema> -g T -o <output> -u <user> <password> -w <timestamp>

Example: DB2exfmt -d test_db -e user -g T -o D:\temp\sql_1_result_DB2exfmt.txt

 -u user password -w l

Query: sql_1.txt

Results: sql_1_result_DB2exfmt.txt

6.3.3 DB2expln

DB2expln是命令行下的解釋工具,和前面介紹的Visual Explain功能相似。通過該命令可以獲得文本形式的查詢計劃。命令如下:

DB2expln -d <db_name> -user <user> <password> -stmtfile <sql.file>-z @ -output <output> -g

Example: DB2expln -d test_db -user user password -stmtfile D:\temp\sql_1.txt

 -z @ -output D:\temp\sql_1_result_DB2expln.txt –g

Query: sql_1.txt

Results: sql_1_result_DB2exfmt.txt

DB2expln將存取計劃以文本形式輸出,它只提供存取計劃中主要的信息,並不包含每一個操作佔用多少CPU、I/O、佔用Buffer的大小以及使用的數據庫對象等信息,方便閱讀。但是DB2expln也會將各項有關存取計劃的信息存入Explain表中,用戶可以使用DB2exfmt察看詳細的格式化文本信息。

6.3.4 錶快照監視器

這是一個命令行參數(運行db2cmd),具體如下:

1.編目節點和數據庫

db2 catalog tcpip node node16 remote 100.1.16.16 server 50000

db2 catalog db intedb at node node16

2.連接到數據庫節點

db2 attach to node16 user db2admin

3.使用

db2 update monitor switches using table on

db2 get snapshot for tables on intedb

db2 update monitor switches using table off

用戶可以查看到一段時間內(從on開始到查看的時間段),數據庫表查詢和更新操作的生效記錄數。如果,某個表有大量讀操作,而寫操作很少,則往往需要優化,優化的方法通常是把where條件裏的某個字段建立索引。

6.4 不同數據庫處於不同實例

一個系統通常有開發環境,性能測試環境,功能測試環境,生產環境等。而且常常存在多個環境在同一臺機器上。這些環境除了共用系統資源外,還會互相影響。開發環境,測試環境可能常常需要重啓數據庫(db2stop、db2start),而這樣做會影響到生產環境。我們建立多個實例,將不同環境的數據庫建立在相對獨立的多個實例裏,這樣可以儘量避免多個環境相互影響。

6.5 開始行動

性能調優是一個大工程,而且包括了很多、很瑣碎的方面,不可能所有的方案都採取,需要針對具體問題進行取捨。進行再多的討論,對性能調優作用甚微。現在需要做的就是一邊嘗試着修改,一邊監控性能的變化,然後決定採用哪些方案。

那麼從現在開始行動吧!


7 參考文獻

1.        DB2 調優參考.txt

2.        AIX 上影響 Oracle 的參數.htm

3.        db2參數.htm

4.        db2參數調整命令.htm

5.        IBM DB2 內存分配與使用策略.htm

6.        基本性能調整.htm

7.        排序堆大小(SORTHEAP)和排序堆閾值(SHEAPTHRES).txt

8.        AIX 中 Paging Space 使用率過高的分析與解決(轉載自IBM).htm

9.        DB2編程序技巧 (六).htm

 

10.    管理指南-計劃.pdf

11.    管理指南-實現.pdf

12.    管理指南-性能.pdf

13.    ANLY建庫(DB2 9, IBM AIX 5.3).doc

14.    DB2表分區技術.txt

15.    DB2分區功能相關測試.doc

16.    調優 DB2 UDB v8_1 及其數據庫的最佳實踐.mht

17.    DB2 基礎 表空間和緩衝池.mht

18.    aix裸設備.txt

19.    針對基礎設計、性能和可管理性的 DB2 最佳實踐.mht

20.    DB2 for z-OS DB2 數據庫設計.mht

21.    關於 DB2 通用數據庫中索引覆蓋的基本事實.mht

 

22.    邏輯卷管理1.mht

 

The Art of SQL

DB2設計與性能優化——原理、方法與實踐

 

 

 

 

 

 

 

 


8索引

8.1索引與目錄

每一本書的前幾頁一般都是目錄,而最後幾頁通常會有一個關鍵字索引。對於數據庫來講系統表(如:sysobjects等)就是目錄,而標字段上的索引就如同書本後面的關鍵字索引。

數據庫中,目錄(數據字典)和索引的區別:目錄縱向、索引橫向。

8.2影響索引作用的因素

8.2.1區分度(檢索比率)

優化器根據統計信息來生成執行計劃,如果數據庫沒有收集索引的統計信息,優化器就無從下手,只能按部就班,通過全表掃描來執行查詢。所以,新創建的索引需要重新運行統計,否則索引無效。

舉一個例子,有個表TABLE1,其中有一個字段COL1取值是“1”、“2”、“3”三種,運行統計的結果是告訴數據庫TABLE1中的數據其中字段COL1的各種取值所佔的比重。示意如下:

“1”- 12%;

“2”- 66%;

“3”- 22%。

假設還有個字段COL2取值和數據所佔的百分比如下:

“A”- 50%;

“B”- 50%。

則查詢語句1:

select * from TABLE1 where COL1 = “1”and COL2 = “A”,

數據庫優化器會優先選擇字段COL1上的索引來定位表中的數據,因爲通過COL1上的索引就可以將結果集迅速定位在一個小範圍內12%。而相反的,對於查詢語句2:

select * from TABLE1 where COL1 = “2”and COL2 = “A”,

數據庫會優先選擇COL2上的索引,因爲對於語句2的查詢條件COL2上的索引具有更好的區分度。

從上面可以看出,數據庫的優化器通常會優先選擇區分度較高的索引(針對於查詢條件,條件不同選擇的索引可能不同)。

數據庫裏的數據是變化的,所以某個時候採集的統計信息,過一段時間後可能會過時,甚至誤導數據庫優化器,這樣同樣會造成運行性能的低下。所以除了,最初建立索引時需要運行統計,在表中的數據發生變化時也需要運行統計。經驗:當表中數據量變化達到10%時,需要重新運行統計。

8.2.2聚集度

範圍掃描

8.2.3表大小

小型表

中大型表

超大型表

8.2.4業務類型

OLTP和OLAP

8.2.5函數與索引

函數,like語句。。。

Substring(col_name, 1, 3) vs. Substring(col_name,3, 3)

like ‘QQQ% vs. like ‘%QQQ’

8.3索引開銷

性能利器

雙刃劍

索引對插入操作的影響(Oracle)

索引對插入操作的影響(MySQL)

比較索引與促發器對性能的影響

8.4索引總結

使用索引實現關鍵數據的高效訪問。但是需要知道每個索引都會給數據庫更新帶來額外的開銷。這就意味着,低效的索引會給數據庫帶來災難。

對於數據庫,我們必須關注關鍵數據的讀取,爲他們提供最高效的訪問路徑。對此,基本策略就是建立索引。在索引提供高效訪問的同時,也帶來了額外的系統開銷。開銷分爲磁盤空間的開銷和處理器開銷。下面我們討論一下處理器開銷。每當在表中插入或刪除記錄時,該表的所有索引必須進行相應調整。每當對已建立索引的字段進行更新時,這種調整也會發生。舉例子說,如果在未建立索引的表中插入數據需要100個單位時間,那麼每增加一個索引就會增加100到250個單位時間。有趣的是,維護索引的開銷與簡單觸發器帶來的開銷大致相當。

在建立索引前線介紹一些最通俗的信息,這些信息來自developWorks,列出這些信息是因爲我覺得這些信息通常情況下是值得參考的:

7.         當要在一個合理的時間內結束查詢時,應避免添加索引,因爲索引會降慢更新操作的速度並消耗額外的空間。有時候還可能存在覆蓋好幾個查詢的大型索引。

8.         基數較大的列很適合用來做索引。

9.         考慮到管理上的開銷,應避免在索引中使用多於5個的列。

10.     對於多列索引,將查詢中引用最多的列放在定義的前面。

11.     避免添加與已有的索引相似的索引。因爲這樣會給優化器帶來更多的工作,並且會降慢更新操作的速度。相反,我們應該修改已有的索引,使其包含附加的列。例如,假設在一個表的 (c1,c2)上有一個索引i1。您注意到查詢中使用了"wherec2=?",於是又創建一個(c2)上的索引i2。但是這個相似的索引沒有添加任何東西,它只是i1的冗餘,而現在反而成了額外的開銷。

12.     如果表是隻讀的,並且包含很多的行,那麼可以嘗試定義一個索引,通過CREATE INDEX中的INCLUDE子句使該索引包含查詢中引用的所有列(被INCLUDE子句包含的列並不是索引的一部分,而只是作爲索引頁的一部分來存儲,以避免附加的數據FETCHES)。

對於數據倉庫(查詢系統數據庫)可以建立較多的索引(索引和數據的比例可以是1:1)。

決定是否使用索引,可以重點考慮檢索比率。即,判斷索引有效性的依據,就使用鍵值作唯一性條件檢索出的數據的百分比。百分比越低,索引越有效。做出這個論斷的前提是一些假設,如磁盤訪問的相關性能。

索引鍵值相關記錄的物理位置是否相鄰也很重要,因爲是通過塊來操作數據的。建立了索引之後,如果索引鍵所指向的記錄散佈於整個表中,即使這些記錄在表中佔的比率很小,但因爲它們分散在整個磁盤上,所以索引的性能就會大打折扣。

另外值得注意的是,函數和類型轉換可能導致索引失效。

 

 

 


9 SQL語句編寫(DB2)

本章來自王鵬飛舞動DB2系列《DB2設計與性能優化——原理、方法與實踐》,P242

9.1謂詞

首先要知道,不合理的謂詞會限制優化器對索引和連接方法的選擇。設計謂詞時要注意下面的原則。

(1)保證選擇謂詞足夠簡潔。選擇謂詞要儘量採用簡單的形式,如:列名 = 常數表達式,這樣便於匹配索引。還應該避免使用類型轉換,如果有類型轉換應該顯式地寫出轉換函數,並放在表達式的常數一邊,例如:

cast( colum_char10 as int ) = 100

應該寫成:

colum_char10 = cast(100 as char(10) )

另外,使用參數標記(ParameterMarker)時,要儘量利用Cast函數表明它的類型,以免產生不必要的類型轉換。

同樣,下面的謂詞都應該寫成更優化的形式:

XPRESSN(C) = 'constant'

INTEGER(TRANS_DATE) / 100 = 200802

WHERE (CUST_ID * 100) + INT(CUST_CODE) = 123456 ORDERBY 1, 2, 3

它們的正確形式應該爲:

C = INVERXPRESSN( 'constant' )

TRANS_DATE BETWEEN 20080201 AND 20080229

WHERE CUST_ID = 1234 AND CUST_CODE = '56' ORDER BY 1,2, 3

(2)使用合理的連接謂詞(Join Predicate)。連接謂詞是選擇連接方法的基本依據。DB2有三種連接方法:嵌套循環、合併連接和散列連接。注意非等式謂詞不能形成合並和散列連接。只有兩個表之間出現至少一個列名相等的等式謂詞時,合併和散列連接纔會被考慮。散列連接更是要求等式兩端的列的長度相等。

爲了使DB2考了儘可能多的連接方法,連接謂詞應該儘量簡單,如列名1 = 列名2。對於等式謂詞要做到等式兩邊的列名長度相等。如果是Varchar,Char類型,它們定義的長度應該相等,如果是Decimal類型,它們的精度應該相同。

(3)不要使用多餘的謂詞。多餘的謂詞不但增加了系統的計算代價,而且會導致中間結果的估算不準確,併產生較差的訪問計劃。例如對於下面的謂詞,(COL_0MONTH = 199903)實際上是多餘的,應該去掉。

( COL_0MONTH = 199705

  OR COL_0MONTH= 199805 )

AND NOT

( COL_0MONTH = 199903 )

9.2多餘的連接

有些連接看似合理,但也許是多餘的。連接會涉及對錶的多次掃描,去掉多餘的連接,就會減少不必要的開銷。比如,下面的查詢:

select T1.*

from (T1 join T2 as Q2

        on T1.id= Q2.id and Q2.value = 1 ) join T2 as Q3

        on T1.id= Q3.id and Q3.value = 2

去掉不必要的連接後,其形式爲:

select T1.*

from T1, (select id

        from T2

        wherevalue in (1, 2)

        group byid

        havingcount(*) = 2) as Q1

where T1.id = Q1.id

這樣減少了對T2表的一次連接,大幅度提高了查詢效率。

9.3子查詢

在SQL語言中,當一個查詢語句嵌套在另一個查詢的查詢條件中時,稱爲子查詢。如果一個來自外部查詢的列出現在Where子句的子查詢中,那麼當外部查詢中的列值改變後,子查詢需要重新查詢一次。查詢嵌套的層次越多,效率越低。因此應當儘量避免子查詢。如果子查詢不可避免,那麼首先首先要在子查詢中儘量去掉多餘的行,其次考慮將子查詢轉換成連接。子查詢轉換爲連接後,可以使DB2有機會考慮索引以及更多的連接方法和順序,從而生成更優的計劃。特別是Exist和IN子句,可以方便的轉換成連接。例如,

select *

from T1

where exists(select * from T2 where T1.c1 = T2.c1)

可以轉換爲,

select distinct T2.c1, T1.*

from T1, T2

where T1.c1 = T2.c1

注意除非T2.c1有唯一性(unique),否則關鍵詞distinct 是必需的,這是爲了保證最終結果和原來的SQL一致。

9.4外連接

要避免不必要的外連接(OuterJoin)。Outer Join會限制連接的順序,從而導致一些較好的計劃無法生成。因此要儘可能避免使用Outer Join,無論是Left、Right或者Full Outer Join。

9.5 UNION ALL的使用

在使用UnionALL時,我們要注意UNION ALL之上的謂詞是否被下推。可以查看Optimized Statement,看看是否每個選擇謂詞都被下推到相應的子查詢中。如:

select *

from (select * from T1

union all

select * from T2) as V1

where c1 between 2000 and 2009

在OptimizedStatement中應該看到選擇謂詞c1 between 2000 and 2009被下推到Union All裏面變成:

select *

from (select * from T1 where c1 between 2000 and 2009

union all

select * from T2 where c1 between 2000 and 2009) as V1

如果沒有下推,可能由於選擇謂詞過於複雜,或者DB2的查詢重寫器無法判定下推謂詞是否會提高效率。這時候如果確信下推後會產生較好的計劃,可以手動改變SQL的書寫形式。還可以考慮適當提高優化級別,使原來沒有下推的謂詞被下推。

9.6 Having子句

檢查Having子句中的謂詞是否可以下推。應儘可能把Having子句中的謂詞。一般情況下,根據一定的規則,Having子句如果不含有聚合函數,會經過邏輯優化被下推到Where子句裏面,但也會出現不下推的情況。爲了避免出現沒有下推的情況,在編寫SQL是就應儘量將能下推的謂詞寫在Where子句裏面。

9.7 OFNR和FFNR子句

OFNR(OPTIMIZE FOR N ROWS)子句使優化器選擇那些執行時能最快得到前N行結果的訪問計劃,不過查詢仍將返回完整的結果集。FFNR(FETCHFIRST N ROWS ONLY)子句顯示查詢結果只需返回N行,這樣減少了返回結果集。根據應用程序的需要使用這兩個子句可以提高SQL語句的性能。

注意DB2不會因爲查詢指定了FETCH FIRST N ROWS ONLY而選擇返回前N行結果最快的訪問計劃。所以應該在使用FETCH FIRST N ROWS ONLY時,同時使用OPTIMIZE FOR N ROWS。

另外注意,如果應用程序要獲取整個結果集,但卻指定OPTIMIZE FOR N ROWS,可能會使性能降低。這是因爲快速返回前N行的訪問計劃並不一定是對於獲取整個結果集最佳的訪問計劃。

9.8使用參數標記

DB2可以通過在動態語句高速緩存中保存訪問計劃和SQL文本,來避免重複編譯一個已編譯過的動態SQL語句。然而,只要謂詞在字面上有一點不同,這個語句與高速緩存中類似的SQL就無法匹配。例如,下面兩個語句在動態語句高速緩存中會被看做不同的語句。

SELECT EMP_ID, EMP_NAME AGE FROM MANAGER_INFO WHEREEMP_ID = 918233

SELECT EMP_ID, EMP_NAME AGE FROM MANAGER_INFO WHEREEMP_ID = 920122

應該考慮把上述語句改成使用參數標記把謂詞常數值傳遞給DB,而不要顯式地在SQL語句中包含它。不過注意,複雜的查詢如果使用參數標記,得到的訪問計劃可能不是最優的。

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章