sql與PB程序的優化


下面內容從CSDN的一篇貼子中找到的。sql

我用過的一個優化方法是:當檢索表和視圖混合的查詢時,若須要檢索參數,且表與視圖都可用於檢索參數的話,應使用視圖做檢索條件,速度將有明顯提高。數據庫

另附兩篇關於 pb 代碼優化的網摘:express

優化你的 sql 和 dw編程

  1、處理 SQL 語句數組

  一、緩衝 SQL 語句 
  在應用程序中,有時須要反覆調用同一組SQL語句,在這種狀況下,能夠經過在應用中爲這些 SQL創建緩衝區來提升執行性能。在缺省狀況下,SQL語句的緩衝區是關閉的,你能夠經過以下語句打開它: 
  SQLCACHE = n 
  n 表示裝入緩衝區的 SQL 語句數量(缺省爲0)。
服務器

  例如: 
  dw_1.SetTransObject(sqlca) 
  SQLCA.dbParm = "SQLCache = 0" 
  dw_1.retrieve()
網絡

  若是將上例的 "SQLCache = 0" 改成 "SQLCache = 25",此句的執行效率將提升五分之一左右。但應注意緩衝區的大小,不然也將影響程序執行的性能。編程語言

  注:此方法對用 ODBC 和 ORACLE 鏈接的數據庫很是有效。ide

  二、捆綁變量函數

  請看下例:

  SQLCA.DBPARM = "DISABLEBIND=1" 
  INSERT INTO DA_DH VALUES("1","河南0") 
  INSERT INTO DA_DH VALUES("2","河南1") 
  INSERT INTO DA_DH VALUES("3","河南2") 
  INSERT INTO DA_DH VALUES("4","河南3") 
  INSERT INTO DA_DH VALUES("5","河南4") 
  INSERT INTO DA_DH VALUES("6","河南5")

  這裏未使用捆綁變量,再插入時 PB 將從新處理每一個帶有新值的SQL語句。

  若是將上例改成:

  SQLCA.DBPARM = "DISABLEBIND=0" 
  INSERT INTO DA_DH VALUES("1","河南0") 
  INSERT INTO DA_DH VALUES("2","河南1") 
  INSERT INTO DA_DH VALUES("3","河南2") 
  INSERT INTO DA_DH VALUES("4","河南3") 
  INSERT INTO DA_DH VALUES("5","河南4") 
  INSERT INTO DA_DH VALUES("6","河南5")

  則系統將把 INSERT 語句按以下格式進行處理: 
  INSERT INTO DA_DH VALUES(?,?) 
  其中 "?" 稱爲佔位符。系統性能將有所加強。

  三、用數據窗口代替 SQL 語句

  一般,爲了得到某些數據,採用數據窗口和 SQL 語句都是可行的,可是PB 對數據窗口和 SQL 語句採用不一樣的處理機制,所以,具備不一樣的效率。

  例:爲裏檢索電話檔案中的用戶名,能夠利用 SQL 語句,將全部的數據檢索到一個多行編輯中,也能夠檢索到一個數據窗口中。

  若是使用第一種方法:

  首先定義一個遊標: 
    DECLARE CUR CURSOR FOR 
    SELECT "DA_DH"."HM" 
    FROM "DA_DH";

  而後能夠: 
    STRING stxt[],st 
    int li 
    open cur 
    do li = li + 1 
    fetch cur 
    into :stxt[li] ; 
    st=st+stxt[li] + "~r~n" 
    loop while stxt[li] <>"" 
    close cur; 
    mle_1.txt = st

  也可使用第二種方法:

  dw_1.settransobject(sqlca) 
  dw_1.retrieve()

  利用 POWERBUILDER PROFILER 工具進行檢查,對比兩種方法所需時間以下

  方法     所需時間 (百分之一秒) 
  SQL 語句   100.9857 
  數據窗口   49.0133

  因爲數據窗口或DATASTORE使用了標準的內嵌代碼,而不是由開發人員進行所有編碼,同時編譯執行的速度比解釋執行的速度快的多,所以在開發過程當中應儘可能使用數據窗口和DATASTORE.即便是必須用SQL語句的時候,也應該儘可能將它們定義爲存儲過程(特別是在多用戶的環境中),以提升應用程序的性能. 

  2、數據窗口的編程和執行

  數據窗口是PB最值得被稱道的, 其具備以下特色: 
  1. 多種顯示方式. 
  2. 多種編輯方式. 
  3. 使用方法簡單. 
  4. 具備多種報表形式. 
  5. 可實現屏幕滾動. 
  6. 可實現數據的有效性校驗. 
  7. 執行性能顯著提升. 
  8. 編程工做變少. 
  9. 能夠在數據窗口內部實現數據哭的更新.

  下面, 我將介紹一些用於提升數據窗口性能的技術.

  1. 減小鏈接數據庫的次數

  連庫操做是很是影響執行速度的操做. 所以在程序中,一旦與數據庫鏈接後就應當儘可能保持與數據庫的鏈接, 減小鏈接數據庫的次數.PowerBuilder 提供裏兩個函數來創建數據窗口與事務對象的鏈接: 
  SetTrans() 
  SetTransObject()

  在程序中應當儘可能使用 SETTRANSOBJECT(), 由於SETTRANS() 函數在每次調用 RETRIEVE(), UPDATE() 等函數以後, 都要執行數據庫的鏈接和斷開操做.

  2. 下拉數據窗口與表的鏈接

  對於數據庫服務器來講, 表的鏈接操做是一項很是大的開銷, 而 POWERBUILDER 提供的下拉數據窗口在某些狀況下能夠代替表的鏈接操做.例如, 爲了在數據窗口上顯示用戶的電話號碼和姓名:若是用表的鏈接的方法, 數據窗口對應的 SQL 語句應是這樣的: 
  SELECT "DA_DH"."DHHM","DA_HTH"."DWM" 
  FROM "DA_HTH", "DA_DH" 
  WHERE ("DA_HTH"."DHHM"="DA_DH"."DHHM")

  一樣的程序可用下拉數據窗口來完成, 這裏再也不具體介紹.可是, 應當注意, 以上兩種方法究竟哪種數據更快, 與表的結構, 表的數量, 鏈接的方法等均有關係, 應當具體分析.

  3. 共享數據

  在一個應用程序中, 某些數據須要頻繁的使用, 若是在每次使用時都從數據庫中進行檢索, 則需佔用大量的服務器資源和網絡資源. 爲了減小開銷, 能夠在客戶端對這些數據只進行一次檢索, 而後容許其它任務共享這些數據.

  例如, 若是有兩個數據窗口, 都須要從第三方表中檢索出用戶的電話號碼, 且此列用下拉數據窗口給出. 若是每次都對電話號碼進行檢索, 則性能較低. 所以, 能夠單獨創建一個關於電話號碼的數據窗口. 在每次打開窗口時, 首先將電話號碼檢索到此數據窗口中, 而後另外兩個數據窗口中關於電話號碼的下拉數據窗口能夠共享此數據窗口中的數據.

  在窗口的 OPEN 事件中編寫以下程序: 
  dw_1.settransobject(sqlca) 
  dw_2.settransobject(sqlca) 
  dw_3.settransobject(sqlca) 
  // 檢索 dw_1 
  dw_1.retrieve() 
  // 使 DW_2 的下拉數據窗口共享 DW_1 
  datawindowchild child1 
  dw_2.getchild('dhhm',child1) 
  child1.settransobject(sqlca) 
  dw_1.sharedata(child1) 
  // 使 DW_2 的下拉數據窗口共享 DW_1 
  datawindowchild child2 
  dw_3.getchild('dhhm',child2) 
  child2.settransobject(sqlca) 
  dw_1.sharedata(child1)

  使用這種方法, 避免了各個數據窗口間物理的拷貝數據, 所以減小了空間上的開銷,提升了應用程序的綜合性能.

  4. 數據窗口間數據的拷貝

  若是須要在數據窗口間共享數據, 應當儘可能使用 SHAREDATA() 函數, 可是, SHAREDATA() 函數並非物理地在數據窗口間拷貝數據, 若是在顯示數據的同時, 還要對數據進行操做, 則須要進行數據的拷貝.

  例如, 要求將 DW_1 中選定的行拷貝到 DW_2 中:

  在窗口的 OPEN 事件中編程: 
  dw_1.settransobject(sqlca) 
  dw_2.settransobject(sqlca) 
  dw_1.retrieve()

  在數據窗口 DW_1 的 ROWFOCUSCHANGED 事件中編寫下列程序: 
  long lr 
  lr = dw_1.selectrow(0,false) 
  lr = dw_1.getrow() 
  lr = dw_1.selectrow(lr,true)

  要完成從 DW_1 到 DW_2 的拷貝工做, 有兩種方法:

  第一種:

  在按鈕 "拷貝" 的 CLICKED 事件中編程 
  long lr 
  lr = dw_1.getselectedrow(0) 
  dw_1.rowscopy(lr,lr,primary!,dw_2,100,primary!)

  執行程序, 利用 POWERBUILDER PROFILER 得出所需時間爲 1.7034(百分之一秒)

  第二種:

  在按鈕 "拷貝" 的 CLICKED 事件中編程 
  dw_2.object.data = da_1.object.data.selected

  執行程序, 利用 POWERBUILDER PROFILER 得出所需時間爲 0.8062(百分之一秒)

  5. 數據窗口屬性的訪問和修改

  A. 數據窗口屬性的訪問

  在程序中訪問數據窗口的屬性有下列幾種方法:

  A1. 採用點表達式訪問

  A2. 應用多個獨立的 DESCRIBE() 函數訪問

  A3. 只使用一個 DESCRIBE() 函數, 採用複合參數訪問多個屬性

  上面三中方法, 一般第一種方法最慢, 第三種方法最快.

  例如: 
  在窗口的 OPEN 事件中 
  DW_1.SETTRANSOBJECT(SQLCA) 
  DW_1.RETRIEVE()

  第一種方法:

  在檢索按鈕的 CLICKED 事件中編程. 
  string dx, dy, dh, dw 
  dx = dw_1.object.da_dh.x 
  dy = dw_1.object.da_dh.y 
  dx = dw_1.object.da_dh.height 
  dy = dw_1.object.da_dh.width 
  st_1.text =dx+","+dy+","+dh+","+dw 
   
  第二種方法:

  string dx, dy, dh, dw 
  dx=dw_1.describe("da_dh.x") 
  dx=dw_1.describe("da_dh.y") 
  dx=dw_1.describe("da_dh.height") 
  dx=dw_1.describe("da_dh.width") 
  st_1.text =dx+","+dy+","+dh+","+dw

  第三種方法:

  string dx, dy, dh, dw 
  st_1.text=dw_1.describe("da_dh.x" +& 
  "da_dh.y" +& 
  "da_dh.height" +& 
  "da_dh.width")

  實驗證實, 第三種方法的速度是最快的. 可是程序的可讀性最差.

  B. 數據窗口屬性的修改

  在程序中修改數據窗口的屬性有下列幾種方法:

  A1. 採用點表達式修改

  A2. 應用多個獨立的 MODIFY() 函數訪問

  A3. 只使用一個 MODIFY() 函數, 採用複合參數訪問多個屬性

  上面三種方法, 一般第一種方法最慢, 第三種方法最快.

  例如: 
  在窗口的 OPEN 事件中 
  DW_1.SETTRANSOBJECT(SQLCA) 
  DW_1.RETRIEVE()

  第一種方法:

  在檢索按鈕的 CLICKED 事件中編程. 
  DW_1.SETREDRAW(FALSE) 
  dw_1.object.da_dh.x = 18 
  dw_1.object.da_dh.y = 16 
  dw_1.object.da_dh.height = 100 
  dw_1.object.da_dh.width = 200 
  DW_1.setredraw(true) 
  st_1.text =dx+","+dy+","+dh+","+dw

  第二種方法:

  DW_1.SETREDRAW(FALSE) 
  dw_1.modify("da_dh.x = 18") 
  dw_1.modify("da_dh.y = 16") 
  dw_1.modify("da_dh.height = 100") 
  dw_1.modify("da_dh.width = 200") 
  dw_1.setredraw(true)

  第三種方法:

  dw_1.modify("da_dh.x=18" +& 
  "da_dh.y=16" +& 
  "da_dh.height=100" +& 
  "da_dh.width=200")

  實驗證實, 第三種方法的速度是最快的. 可是程序的可讀性最差.注意, 在方法一和方法二中, 都使用的 setredraw() 函數以減小屏幕的重繪, 不然, 執行速度將嚴重降低.


 6. 數據窗口中數據的訪問

  在程序中, 常常會須要動態的修改數據窗口中的數據. 對此, PB 提供了多種方法, 各類方法在性能上會有一些差別.

  A. 數據窗口中數據的訪問

  目的: 將數據窗口中的電話號碼存放在一個數組中.請比較下面兩中方法.

  方法一: 
  string da_dh[] 
  long ll,i 
  ll = dw_1.rowcount() 
  for i = ll to 1 stet -1 
  da_dh[i] = dw_1.getitemstring(i,"dhhm") 
  next

  方法二: 
  string da_dh[] 
  da_dh[] = dw_1.object.dhhm.current

  測試發現, 第二種方法比第一種方法快將近一倍. 數據量越大這種差別越明顯.

  B. 數據窗口中數據的修改

  目的: 修改數據窗口中的電話號碼列的值.

  請比較下面兩中方法.

  方法一: 
  dw_1.setitem(i,"dhhm",l_name)

  方法二: 
  dw_1.object.name[i] = l_name

  測試發現, 第二種方法比第一種方法快將近一倍. 數據量越大這種差別越明顯.

  7. 數據窗口事件對性能的影響

  對於數據窗口控制中常常發生的事件, 應當儘可能減小其中的程序代碼. 特別是以下事件: 
  a. itemchanged 
  b. editchanged 
  c. itemfocuschanged 
  d. pbm_dwnkey 
  e. rowfocuschanged 
  f. retrieverow

  在這些事件中的任何處理程序, 都會下降應用程序的處理速度. 因此應當儘可能減小這些事件中的處理程序, 必要時, 能夠考慮只將重要的代碼放在這些事件中, 而將剩餘的代碼放在一個傳遞的事件中.

  例如,若是須要用到數據窗口的 ROWFOCUSCHANGED 事件,能夠爲數據窗口定義一用戶事件 "UE_RE",而在數據窗口的 ROWFOCUSCHANGED 事件中寫以下代碼: 
  PARENT.postevent("ue_re")

  在 UE_RE 事件中再編寫相應的程序代碼,如: 
  string code 
  dw_1.selectrow(0,false) 
  dw_1.selectrow(rownum,true) 
  code = getitemstring(dw_1,rownum,"dhhm") 
  dw_2.retrieve(code)

  另外, 爲了得到當前行號,應儘可能使用數據窗口的 CURRENTROW 變量,而少用 GETROW() 函數。

  8. 數據窗口的列名稱與列編號

  對數據窗口的某列進行訪問, 能夠採用該列的名稱, 也可使用該列的編號。

  例如: 
  採用列編號: 
  dw_1.object.data[ll_row,2] 
  dw_1.getitemstring(3,2)

  採用列名稱表示某列: 
  dw_1.object.article_text[ll_row] 
  dw_1.getitemstring(3,"dhhm") 
  dw_1.setitem(3,"date",1999-03-31) 
  ... 
  
  對於以上兩種方法,若是隻進行一次查詢,在速度上並無太大的區別,若是須要循環訪問數據窗口上的某一列,則速度上的差別就表現的比較明顯,採用第一種方法要快, 可是程序的可讀性比較差。可是,在使用函數時(如 GETITEM() 和 setitem() ), 執行速度每每沒有很大差異。

  9. 計算域

  數據窗口的計算域會對數據的操做性能產生影響。 若是數據窗口中包含許多複雜的計算域,將嚴重影響數據窗口的執行速度。


-----------------------------------------------------------------------------------------------


條件和循環類語句的優化

現今計算機的運行速度已經很快了,而且因爲老闆時常在耳邊念着緊箍咒,所以,咱們有意或者無心的忘記優化咱們的代碼,只要能完成任

務就好了(我也是)。不過,咱們閒下來的時候,不妨也來看看咱們的代碼是否有須要改進的地方。下面就是我以爲值得優化的幾種狀況。


第一種狀況:

  IF condition1 AND condition2 THEN

      //Code goes here.

END IF

IF condition1 THEN

      IF condition2 THEN

            //Code goes here.

      END IF

END IF


對於書寫的第一種方式,因爲PB編譯方式與常見的方式不一樣,就是不管條件1的值如何,都要對條件2進行運算。這樣一來,當條件1爲false

時,就可能要無謂的對條件2進行運算了。就按隨機的機率而言,可能會多進行一半的運算。所以,對於大多數狀況而言,我想最好是以第二

種方式書寫。固然,特殊狀況也是有的,那就是你的確想對條件2進行運算。相似地,對於or也同樣。


IF condition1 OR condition2 THEN

      //Code goes here.

END IF

IF condition1 THEN

      //Code goes here.

ELSE

      IF condition2 THEN

            //Code goes here.

      END IF

END IF 
  第二種狀況:


IF NOT condition THEN

      //Code goes here.

END IF

IF condition THEN

      //No code goes here.

ELSE

      //Code goes here.

END IF


對於上一種方式,條件表達式返回false而且再進行一個非運算,才執行下面的代碼。這樣相對於下面一種書寫方式可能多執行了一個非運算

。若是你們有什麼疑問,您不妨測試一下下面這個例子:


//小測試:其中的判斷條件只是爲了表示一下,實際狀況可能更復雜。


long i                  //計數器

long ll_start          //執行開始時間

long ll_used1      //方式一耗時

long ll_used2      //方式二耗時


//方式一

ll_start = Cpu()

for i = 1 to 900000

      if not (1 > 1) Then

            i = i

      end if

next       

ll_used1 = Cpu() - ll_start

//方式二

ll_start = Cpu()

for i = 1 to 900000

      if 1 > 1 Then

           

      else

            i = i

      end if

Next

ll_used2 = Cpu() - ll_start


//查看結果

If ll_used2 > ll_used1 Then

      MessageBox("提示","前者運行時間短!")

Else

      MessageBox("提示","後者運行時間短!")

End If


可能有人會說,用下面的那種方式,若是在條件表達式返回false的時候,那麼,if下就沒有代碼,這樣看起來就不太舒服。的確是這樣。因

此,咱們在寫成上面的那種方式時,儘可能保持不要使用not運算,而保持條件表達式自己就返回但願的true值。

  第三種狀況: 
IF condition1 THEN

      //condition1

ELSEIF condition2 THEN

      //condition2

ELSEIF condition3 THEN

      //condition3

ELSE

      //Other

END IF

choose case /*expression*/

      case /*item*/

            /*statementblock*/

      case /*item*/

            /*statementblock*/

      case else

            /*statementblock*/

end choose


對於形如這樣的表達式,我想咱們通常都沒去考慮前後順序。可是,其實咱們應該把最可能發生的狀況,放在前面,這樣能夠避免在對一大

堆條件進行判斷後,纔到咱們真正須要運行代碼的地方。 
  

第四種狀況:


 FOR ... TO ...

   

      IF condition THEN

            //true

      ELSE

            //false

      END IF

   

NEXT

IF condition THEN

      //true

      FOR ... TO ...

            //Code goes here

      NEXT

ELSE

      //false

      FOR ... TO ...

            //Code goes here

      NEXT

END IF


儘管下面這種書寫方式,看起來好象代碼多了一些,可是卻極大的避免了在每一個循環中都進行條件判斷。其實,一個原則就是,咱們應當盡

量避免在循環中進行條件判斷,而是把條件判斷放到循環體的外面進行。


其實,真正對於PB語言有特殊性的,也就是第一種狀況,對於後面三種狀況,對於別的編程語言,我想也一樣適用。


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xiongxiao/archive/2009/01/13/3764759.aspx

相關文章
相關標籤/搜索