程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> DB2數據庫 >> DB2教程 >> 減少與 DB2 for z/OS 的會話:第 3 部分:以不同的思路思考普通事務

減少與 DB2 for z/OS 的會話:第 3 部分:以不同的思路思考普通事務

編輯:DB2教程

在前面兩個專欄中,談到不必要的 SQL,並給出了執行次數過多的SQL 例子,以及應當由更新的、性能更優的 SQL 來替代的例子。在本專欄中,將講述更多 SQL 應當被推遲、結合、或者完全避免的情況,最終目的都是減少與DB2 的對話。

通過三步移除不必要的重復讀取(re-reads)

Screen-display 應用因其大量不必要的重復讀取而出名。我們讀取一個圖像並顯示;用戶變更屏幕上的值並點擊功能鍵來更新;程序獲得控制權並重新讀取該行(通常此時利用使用 FOR UPDATE OF 的 CURSOR )。FETCH 之後,程序進行 “前後” 檢查,來查看在進行屏幕顯示時,是否有不同用戶對該行做了改動。

如果該行與最開始時一致,則用戶的 UPDATE 操作完成。如果行中的任何列改變了,相應的信息/錯誤將返回給用戶。

解決這一不必要 SQL 問題的方法是,采用 “樂觀鎖定(optimistic locking)” 技術。我們確信大多數情況下,行不會在屏幕顯示時改變。我們的 UPDATE 杯子是半滿,而不是半空。因此,將不必重新讀取該行而直接進行 UPDATE 操作。但是,我們並不笨;我們將使用試錯(trIEd-and-true)技術來確保針對未變更行的 UPDATE 操作已經完成:我們在子句 WHERE 中增加了一個或多個謂詞,來測試變更。有很多選項可用於測試變更,其中一些允許比其他有更多的流量。例如,我們可以:

設計表來包含 DB2 維護的 ROW UPDATE TIMESTAMP(DB2 9 中的新特性),並在 WHERE 子句中包含一個謂詞,來檢查該列,從而確定該值是否與從列中讀取的初始值相同。

將用戶維護的、最後更新的時間戳與其初始值對比(並在 SET 子句中重置該時間戳),來確定從該行取得圖像後,該行沒有任何變化。

在行的每個列中包含 WHERE 子句謂詞,來確定每列的值是否與其初始值相同。

在重要的、與我們相關的列中包含 WHERE 子句謂詞。我們肯定想確保行仍然合格,並且我們想驗證我們所選的、未變化的列。

為提高性能而進行的主要變化

具有 TRANDATE、PROCESS-DATE、以及 CUSTNO 的索引,希望 FETCH 行,並提交報告,如下情況的行將被刪除:時間超過 3 個月、無效、並在程序工作存儲中的清單中發現 CUSTNO。

您可以:

Declare Cursor csr-delete-old-rows for 
 Select ponbr, custno, trandate, process-date 
 From bigtable 
 Where trandate < current date - 3 months 
 And status = :hv-inactive 
     
Open csr-delete-old-rows 
 
Fetch csr-delete-old-rows into 
 :hvponbr, :hvcustno, :hvtrandate, :hvprocess-date 
 
Write to a report 
 
Delete from bigtable         
 Where current of csr-delete-old-rows 

如果有 3,000 個索引行指向具有 TRANDATE 超過 3 個月的表行,但是,3,000 個表行中只有 500 個其 STATUS為 “inactive”,那麼最壞情況是您需要:

為 OPEN 進行 CURSOR 設置,CONNECT 到 DB2

為每個 FETCH,CONNECT 到 DB2。然後,對於 3,000 連接中的每個:
a. 對索引樹 multi-level 中的頁,發出多個 GET PAGE 請求
b. 讀取 6 個索引項的平均值
c. 對於 6 個 RIDs 索引中的每個,向表發出 GET PAGE 請求,然後可能需要等待 I/O 同步
d. 完成對表的 GET PAGE 請求(並讀取 I/Os)後,向這 6 個表行應用 STATUS 謂詞,拒絕 5 個並接受 1 個

向程序返回一個行

在 500 個合格的行中,只有 25 個 CUSTNOs 在工作存儲列表中(在從 DB2 返回後,在程序中拒絕行的條件稱為 “Stage 3 謂詞” —— 並且 Stage 3 謂詞比 Stage 2 謂詞更糟糕)

對每個完全合格行,再次對 DB2 執行 CONNECT,此次進行 DELETE 操作(25 個連接)

為多達 528 CONNECTs 重復 24 次,並且對每個索引和表進行太多的 GET PAGEs。

那麼如何在這種條件下減少對話的數量?我建議做 4 方面改善(您可能還記得在 上一專欄的第 2 步 中的建議):

如果可行,在索引中增加 STATUS,來使得有效性只適用索引

改變 CURSOR 來使 ROWSET POSITIONING 每次讀取多行

利用 SELECT FROM DELETE 來查看行

通過將數字 INSERT 到 CREATED GLOBAL TEMPORARY TABLE(例如,CTT_CUST)並通過在 SQL 中使用臨時表,去掉 STAGE 3 取消資格(程序檢查 CUSTNO)

Declare Cursor csr-select-and-delete-old-rows 
 With rowset positioning 
 For 
 Select ponbr, custno, trandate, process-date 
 From final_table 
 (Delete from bigtable 
 Where trandate < current date - 3 months 
  And status = :hv-inactive 
  And custno in (select custno from ctt_cust) 
Open csr-select-and-delete-old-rows 

(一個 CONNECT)

Fetch rowset from final_table 
For 100 rows into 
:hvponbr-array, :hvcustno-array, :hvtrandate-array, :hvprocess-date-array 

(一個 CONNECT ,以及 100 個以上針對第 26 行返回的 SQLCODE)

Close csr-select-and-delete-old-rows

(一個 CONNECT)

新的最佳情況是,您將:

為 OPEN 進行 CURSOR 設置,CONNECT 到 DB2

為 FETCH,CONNECT 到 DB2,並且:
a. 對索引樹中的頁發出 GET PAGE 請求
b. 讀取 25 索引項,在讀取表之前,完全限定該行
c. 對 25 個 RID 中的每一項,向表發起 GET PAGE 請求(如果我們很幸運,並且有些行共享一些頁,可能會少做點 GET PAGEs 操作)
d. 對於每個 GET PAGE,需要做 READ I/O 操作
e. 當發現每行時,DELETE 它
f. 將每行中已 SELECT 的列插入 final_table
g. 向程序返回 25 行

寫入報告:

Close csr-select-and-delete-old-rows 

(一個 CONNECT)

利用前面的 4 項技術,將對話從 528 次減少到 3 次,同時,將表 GET PAGE 請求的數量從 3,000 次降低到至多 25 次。

消除 Stage 3

我想詳細闡述上述第 4 個建議改進(去除 STAGE 3 取消資格)。作為咨詢人員,我發現主要的公共編碼失誤之一是在程序中,而不是 DB2 中驗證並拒絕行。

這些 STAGE 3 謂詞,特別是拒絕大部分行的那些,通常是不使用 WHERE 子句的舊有 VSAM 邏輯的結果。我們采用鍵控讀取,然後向記錄應用程序編碼的 IF/THEN/ELSE 邏輯。IF/THEN/ELSE 邏輯是搞清楚如何使用 WHERE 子句謂詞的良好基礎,因此在 DB2 地址空間中行能夠被快速拒絕。

結束語

我編寫這個三部分系列文章,來強調完全消除或者延遲 —— 直到最後一刻 —— 與 DB2 對話的重要性。今後,在為每個 SQL 語句編碼時,我希望會有一個小 BonnIE 坐在您身邊,問道:“這有必要麼?能否一次對多個行進行讀/維護?能否推遲這一 SQL,直到確保需要這樣做?”

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved