程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> DB2數據庫 >> DB2教程 >> DB2數據庫移植常見問題全面解析

DB2數據庫移植常見問題全面解析

編輯:DB2教程

安裝與配置

在 Linux 下重新安裝 DB2 之後無法建立 DB2INST1 的實例,提示已經存在

解決辦法:刪除 /var/db2/v81 目錄,再重新創建實例;

原因分析:在重新安裝 DB2 之前,需要卸載原 DB2 安裝環境,其中很重要的一步就是,使用 db2idrop 命令刪除 DB2INST1 實例, 如果不刪除,再次安裝 DB2 之後,則無法建立相同名稱的數據庫實例。db2idrop 命令在 /opt/IBM/db2/V8.1/instance 目錄下,以下為示例:

清單 1. db2idrop 命令示例

/opt/IBM/db2/V8.1/instance/db2idrop db2inst1

在Solaris 5.8 下安裝 DB2 後卻無法創建實例,提示 shmmax 需要調整

解決辦法:編輯 /etc/system 文件,修改共享內存參數和消息隊列值,重啟機器後再建實例;

原因分析:DB2 在 UNIX 系統上需要使用 IPC 通信,所以內核參數共享內存和消息隊列是關鍵指標,如果不能達到 DB2 要求數量,則 DB2 無法正常工作,其具體數字不易記憶,但可以查看 db2diag.log,裡面記錄了 DB2 所需要的具體數字,依照該數字更新內核參數即可。

DB2 Runtime ClIEnt 可否不安裝開發工具包,只安裝足夠客戶端工作的組件,以方便模擬客戶實際應用環境進行測試?

解決辦法:DB2 Runtime ClIEnt並不包含開發工具包。其功能就是只提供客戶端工作的組件包。

一個裸設備無法同時分配給兩個數據庫,這樣無法建立兩個數據庫服務器共享同一個裸設備

解決辦法:把這兩個數據庫分別建在不同的實例上,將其中一個實例停下,第二個實例啟動,分配裸設備給該活動實例上的數據庫,分配完畢後將活動實例停下,啟動第一個實例,重復先前分配裸設備的操作到第一個實例,即可實現當一個數據庫停下時,該裸設備數據可以完全被另外一個數據庫接管,從而實現共享。

-

原因分析:一個容器是無法同時分配給兩個活動數據庫的。必須針對兩個實例來操作,分配給一個實例時另一個實例必須處於不活動狀態。

在 Linux 上 DB2 安裝完成後,不能綁定 License,報 DBI1430N 錯誤

解決辦法:

1.更新系統時間到當前時間。使用 Linux 中的 DATE 命令;

2.使用 db2licm 命令綁定 License:

清單 2. 綁定 License 命令示例

./db2licm -a db2ese.lic

在Linux 上 DB2 實例創建不成功,返回錯誤碼 DBI1281E

解決辦法:正確設置主機名;

原因分析:DB2 創建實例時要取主機名,如果主機名設置不正確,則會報告無法初始化實例的錯誤,也就是 DBI1281E,可以首先用 uname 或者 hostname 查看是否有主機名,進一步可以用 ping 命令驗證主機名是否正確,如果 ping 不通則不正確,還可以檢查 /etc/hosts 查看 IP 和主機名的對應關系是否正確。

連接數據庫

SuSE Linux C shell 環境下,無法連接數據庫

解決辦法:在cshell下,執行以下腳本設置環境,或將該命令加到 Linux 用戶配置文件中:

清單3. 設置環境

source /sqllib/db2csrhc

原因分析:在 Linux 下,根據不同的 shell,需要執行不同的腳本來設置環境。

清單 4. 在不同的 shell 環境下設置

. /sqllib/db2profile (B shell 或 K shell)

source /sqllib/db2csrhc (C shell)

CLP 連接數據庫服務器返回錯誤,提示 codepage 無法轉換,按提示更改代碼頁後仍然無法連接

解決辦法:在 CLP 中運行 db2 terminate 後再重新連接即可;

原因分析:在 CLP 中 codepage 更改不會即時生效,必須斷掉當前連接再連才會生效。

Solaris 5.8 下用命令行方式無法連接數據庫,提示遇到錯誤 SQL1084C

解決辦法:編輯 /etc/system 調整內核參數,重啟機器;

原因分析:查看 db2diag.log 可以發現消息隊列錯誤,進一步發現該機器上的內核參數的消息隊列值被改為 4096,DB2 需要 65535,更改這個參數重啟機器和數據庫,再連成功。

在Linux C Shell下創建新的 DB2 用戶之後,用該用戶無法連接數據庫

解決辦法:在該用戶 home 目錄下尋找 .cshrc 文件,如果沒有則手工創建一個,然後在該文件中加入以下一行,然後重新登陸或者使用 source .cshrc 即可連接數據庫。

清單5. shell 環境設置

source /sqllib/db2cshrc

原因分析:創建的用戶所用的 shell 是 C shell,調用的是 .cshrc,該文件不存在,手工創建該文件,並在該文件中調用 sqllib/db2cshrc 後即可以正常連接數據庫。

存儲過程

在Stored Procedure 中如何判斷一個系統文件是否存在

解決辦法:使用 Java 開發一個 UDF, 將文件全名通過參數傳遞給這個 UDF,在 UDF 中判斷系統文件是否存在然後返回結果代碼;

原因分析:存儲過程的主要目標是對數據庫對象的操作,對文件系統操作需要借助於外部語言開發用戶自定義函數,DB2 中提供了用各種外部語言開發函數的機制,所以推薦用 Java 開發 UDF 後,由該存儲過程來調用。

DB2 SQL PL 的 HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND 無法捕獲 SQLCODE=-727 和 SQLCODE=-911 的異常

解決辦法:將 DB2 補丁升級到 DB2V8 FixPack9;

原因分析:在 DB2 V8 FixPack7 上的確存在該問題,在 FixPack9 中已經解決。

備份與恢復

DB2中可否查詢最近一次全備份執行的時間以及全備份文件存放的路徑

解決辦法:在 CLP 中可以使用 list history backup all for 命令查看,如需要在存儲過程中使用,可使用表函數查詢:

select from table(snapshot_database('sample',-2)) as t

原因分析:snapshot_database() 是 DB2 中提供的表函數,可以返回當前數據庫的一些信息,其中包括了數據庫上次備份的時間信息。第一個參數是數據庫名,第二個參數是數據庫分區標志,-2 代表所有分區,-1 代表當前分區。

如何在數據庫恢復的時候重定向表空間

解決辦法:使用如下命令,詳情請參見《DB2備份和恢復》簡明手冊:

清單6. 在數據庫恢復的時候重定向表空間

RESTORE DATABASE SAMPLE FROM "C:TEMP" TAKEN AT 20050626155952 REDIRECT;

SET TABLESPACE CONTAINERS FOR 0 IGNORE ROLLFORWARD CONTAINER OperaTIONS

USING (PATH "C:DB2NODE0000SQL00005SQLT0000.0");

RESTORE DATABASE SAMPLE CONTINUE;

數據操作

如何對應 SQLServer 的 InsertBulk 命令?

解決辦法:使用 load 命令。

如何給 VARGRAPHIC 類型字段設置缺省值?

解決辦法:將數據庫建為 UTF-8 格式的數據庫。

表中有 long varchar 字段,在存儲過程的游標中,以 select distinct varchar(該字段)……方式選擇記錄,但編譯通不過

解決辦法:把 distinct 去掉;

原因分析:如果有 long 型字段,加 distinct 關鍵字就失去意義而且十分影響性能,另外該列在原來的 Oracle 應用中也只是定義為 varchar(4000),建議在 DB2 中仍設為 varchar 型,同時將該表所在表空間的 pagesize 加大,由缺省的 4k 設為 16k 或 32k。

DB2存儲過程中的異常處理如何寫,與Oracle中的有何區別?

解決辦法:DB2 中使用以下 SQL 語句聲明和處理異常:

清單7. 聲明和處理異常,方法一

DECLARE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND

BEGIN

END;

或者也可以針對某一sqlstate定義相應的錯誤處理句柄,示例如下:

清單8. 聲明和處理異常,方法二

DECLARE condition_name CONDITION FOR SQLSTATE value;

DECLARE EXIT HANDLER FOR too_many_rows

BEGIN

...

END;

如何查詢數據庫中用戶已定義的表?

解決辦法:select * from syscat.tables;

原因分析:DB2 提供了一組視圖用以用戶查詢數據庫對象,這些視圖統一存放在 SYSCAT 模式下,這些視圖幾乎包含了所以的數據庫對象編目信息,包括表、視圖、名字空間、存儲過程等等。用戶可以在《DB2 UDB SQL Reference Volume 1》SQL Reference 1 的 Appendix D 中找到這些視圖的詳細定義。

如何查詢數據庫中用戶已定義的 sequence?

解決辦法:使用 select * from syscat.sequences。

如何用SQL語句獲得表空間的當前使用率?

解決辦法:可以使用如下 SQL 語句查詢,在用該語句獲得了表空間已用頁數,可用頁數等信息後,即可計算出表空間當前使用率:

清單9. 獲得表空間頁數信息

select tablespace_name, page_size, usable_pages, used_pages, free_pages

from table( snapshot_tbs_cfg( 'sample', -1 ) ) as t

where t.tablespace_type = 0 and t.tablespace_name=

在 Oracle 中可以將游標結果集通過 BULK 方式存入宿主數組中,DB2中如何實現?

解決辦法:DB2 中不支持 BULK 方式,其替代方式是定義相應的數組,然後以循環方式每次從游標結果集中 fetch 一條記錄到數組元素中。

DB2中如何用 SQL 語句取出滿足條件的結果集的前N條記錄?

解決辦法:使用 select * from where fetch first row only

Oracle中有 trunacte 表的功能,速度非常快,它只是把表標志設為空,並不發生刪除數據的 IO 操作,DB2 中如何做類似操作?

解決辦法:可以先 drop 表,再重建該表

原因分析:Oracle 中 trunacte 表的速度之所以快,是因為它不記日志,只是直接把表的結構信息刪除了,並不發生刪除數據的 IO 操作。DB2 中 drop 表,也不會引起數據 IO 和日志記錄,從而達到相同的效果。但前提是你預先有創建表的結構。否則不要隨意 drop 表。

Oracle 有 truncate,DB2 中建議使用 drop,然後再 create 表,這樣好還是 alter 表好?

解決辦法:Oracle 的 truncate 是直接把表的數據清空,但不記日志,所以速度很快。DB2 中 drop 表也避免了大量記錄記入日志的問題,再重建表就達到了快速清空表的目的。但 alter 是用於修改表結構的,和表的數據操作沒有關系。

在一次性導入大量數據到表中時,會因為寫日志而影響性能,如何提高該操作的性能,在導入數據後,需要做更新統計操作,如何做?

解決辦法:一次性導入大量數據時為了提高性能,可以使用 alter table activate not logged initially 在該事務中關閉該表的日志選項,然後執行數據導入,在該事務結束後,該表日志開關自動打開。在導入大量數據後,為了提高查詢性能,再運行 runstats on table 命令更新查詢統計信息。

提示:必須在一個事務中執行關閉日志和數據導入才會不記日志,當前事務結束後日志開關會自動重新打開。

DB2 中如何定時執行一些任務,如表的清空等維護操作?

解決辦法:在任務中心圖形界面中將維護腳本導入,並設定定時調度的時間周期,任務中心會自動調度該任務。運行任務中心的前提是數據庫服務器上已裝有任務中心,並已編目工具目錄數據庫,如果沒有工具目錄數據庫,請按以下步驟操作:

a.使用 create db taskdb 創建一個新的數據庫,以用於工具目錄數據庫;

b.使用 db2admin start 啟動數據庫管理服務器,如果已經啟動,進入第三步;

c.使用 db2 create tools catalog toolscat use existing db taskdb 編目工具目錄數據庫。

DB2 中如何實現為一個 DMS 表空間自動添加容器的腳本?

解決辦法:可以先計算表空間當前可用大小,如小於某個設定值,則用 Alter tablespace add (...) 語句添加新的容器到表空間。計算表空間可用大小的方法可以參照問題“如何用sql語句獲取表空間的當前使用率?”

用 UDF 實現了將 TimeStamp 類型的一個變量轉換成 Date 型,但卻無法將該 UDF 用於 Group By 子句

解決辦法:可以使用 With 語句將需要 Group By 的字段先預先處理。如:with t1(col1) as (select func1(timecolumn) from t2) select col1 from t1 group by col1。With 語句中的 func1()為 UDF,實現了將 timestamp 轉換為 date 的功能,其結果通過 with 語句被定義為一個 t1 中的虛列 col1,然後在 t1 中按 col1 分組。注意上面是一條語句,中間沒有分隔符。

如何做類型轉換才能將 VARGRAPHIC 類型的數據用在 LOCATE 函數中?

解決辦法:先將 VARGRAPHIC 轉換成 VARCHAR。然後再用於 locate 函數。

原因分析:LOCATE 函數只能接受字符串作為輸入,所以必須將 VARGRAPHIC 先轉換成 VARCHAR。同時在數據庫編碼格式上有要求,只有用 Unicode codepage 創建的數據庫才能實現 VARGRAPHIC 到 VARCHAR 的轉換。所以之前要用 UTF-8 CN_ZH 方式創建數據庫。

如何使用 DB2 JDBC TYPE 4 方式連接數據庫?

解決辦法:將 JDBC Driver 配置為 com.ibm.db2.jcc.DB2Driver,在程序中數據庫 URL 指定為 jdbc:db2://server:port/alias。Server 是指數據庫服務器所在主機名或 IP;port 是數據庫服務端口號,缺省是 50000;alias 是數據庫別名。編譯時需要 db2jcc.jar,記得把它指定在 classpath 中。

如何將一個 timestamp 類型轉換為 yyyymmdd 格式?

解決辦法:可以使用用戶自定義函數(UDF)來實現。以下是一個廣為流傳的轉換函數代碼:

清單10. 將 timestamp 類型轉換為 yyyymmdd 格式

create function ts_fmt(TS timestamp, fmt varchar(20))
returns varchar(50)
return
with tmp (dd,mm,yyyy,hh,mi,ss,nnnnnn) as
(
select
substr( digits (day(TS)),9),
substr( digits (month(TS)),9) ,
rtrim(char(year(TS))) ,
substr( digits (hour(TS)),9),
substr( digits (minute(TS)),9),
substr( digits (second(TS)),9),
rtrim(char(microsecond(TS)))
from sysibm.sysdummy1
)
select
case fmt
when 'yyyymmdd'
then yyyy || mm || dd
when 'mm/dd/yyyy'
then mm || '/' || dd || '/' || yyyy
when 'yyyy/dd/mm hh:mi:ss'
then yyyy || '/' || mm || '/' || dd || ' ' ||
hh || ':' || mi || ':' || ss
when 'nnnnnn'
then nnnnnn
else
'date format ' || coalesce(fmt,' ') ||
' not recognized.'
end
from tmp@

將上述代碼保存在一個文本文件中,假設保存到 func.db2 中,使用以下命令創建函數:db2 –td@ -f func.db2。然後即可使用該 UDF 進行時間格式轉換。該函數可以根據輸入的 timestamp 轉換為多種格式,包括 yyyymmdd,mm/dd/yyyy,yyyy/dd/mm hh:mi:ss,或者返回毫秒數(nnnnnn)。

在 SQL 存儲過程中有('每月'||COALESCE(VAR, '')||'元')語句時,編譯無法通過

解決辦法:客戶端 codepage 和腳本的編碼格式不同,所以服務器端無法識別腳本命令,把客戶端 codepage 設為 1386 即可。

Oracle 中有一個函數 DBMS_SQL.VARCHAR2_TABLE,可以傳入一個以某個分隔符為分隔的字符串,該函數將該字符串以分隔符拆分,返回給調用者一個數組或是表,DB2 中如何實現類似功能?

解決辦法:用全局臨時表實現;

原因分析:Oracle 中的 varchar2_table 其實是集合的概念,在 DB2 中不支持集合。DB2 通常做法是聲明全局臨時表(DGTT),第一列存儲記錄順序,第二列存儲數據。以下是示例,在聲明後即可向該表中插入和查詢數據,效果和集合相同。

清單 11. 實現拆分

DECLARE GLOBAL TEMPORARY TABLE SESSION.temp_emp_list

(num integer, EmpName varchar(30))

WITH REPLACE

ON COMMIT PRESERVE ROWS NOT LOGGED;

DB2 無法對允許空值的列建唯一性索引

解決辦法:將該列屬性設為不允許為空;

原因分析:空值在數據庫中被認為是不確定值,任何其他值與空值組合,結果仍然是空值,不具備唯一性,所以 DB2 不允許空值列作為唯一鍵的索引列。

同一張表的索引可以放在不同表空間中嗎?

解決辦法:在創建表的時候使用 INDEX in tablespace-name 選項,在該表上創建的索引將存放在指定的表空間上;

原因分析:表數據,表索引,以及表中的 long 型數據可以分開存放在不同的表空間。可以提高性能。

用UDF 調用存儲過程總是編譯通不過,報關鍵字沖突錯誤

解決辦法:把該 UDF 改造成存儲過程;

原因分析:DB2 中 UDF 主要用於邏輯運算和處理,存儲過程則偏重於處理數據庫對象,如表數據的增刪查改,所以兩者的用途不同決定了其使用方式也不同,UDF 使用的是內嵌的 SQL 語句,是 SQL 語言的子集,不能執行動態 SQL,如果 UDF 調用存儲過程,則會導致 SQL 嵌套上的混亂,因為 UDF 通過調用存儲過程實現了 SQL 全集,這是不允許的,所以報關鍵字沖突,把該 UDF 改為存儲過程即可。

建議對於不涉及數據庫表操作的業務邏輯可以用 UDF 實現,如邏輯算法,文件操作,系統調用等,而涉及到數據庫表操作的功能則交給存儲過程來實現。存儲過程可以調用 UDF。

工具使用

如何在 CLP 中查看表結構

解決辦法:使用 db2 describe table 命令。

用開發中心遠程調試存儲過程,可以構建,但構建並調試卻不能成功

解決辦法:在遠程數據庫上安裝 DB2 開發包;

原因分析:在遠程調試時將會調用遠程數據庫上的開發包,所以遠程服務器一定要裝有開發包才可遠程調試。

如何將部署在 DB2 數據庫上的存儲過程導出為可執行腳本,以便在其它機器上部署

解決辦法:在開發中心中可以導出存儲過程為腳本,前提是之前創建存儲過程的時候沒有指定 hide body。

如何讓 DB2 自動運行 runstat

解決辦法:使用 db2 update db cfg using auto_runstats on 命令。

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