DB2數(shù)據(jù)庫移植常見問題全面解析
安裝與配置
在 Linux 下重新安裝 DB2 之后無法建立 DB2INST1 的實例,提示已經(jīng)存在
解決辦法:刪除 /var/db2/v81 目錄,再重新創(chuàng)建實例;
原因分析:在重新安裝 DB2 之前,需要卸載原 DB2 安裝環(huán)境,其中很重要的一步就是,使用 db2idrop 命令刪除 DB2INST1 實例, 如果不刪除,再次安裝 DB2 之后,則無法建立相同名稱的數(shù)據(jù)庫實例。db2idrop 命令在 /opt/IBM/db2/V8.1/instance 目錄下,以下為示例:
清單 1. db2idrop 命令示例
/opt/IBM/db2/V8.1/instance/db2idrop db2inst1
在Solaris 5.8 下安裝 DB2 后卻無法創(chuàng)建實例,提示 shmmax 需要調(diào)整
解決辦法:編輯 /etc/system 文件,修改共享內(nèi)存參數(shù)和消息隊列值,重啟機器后再建實例;
原因分析:DB2 在 UNIX 系統(tǒng)上需要使用 IPC 通信,所以內(nèi)核參數(shù)共享內(nèi)存和消息隊列是關(guān)鍵指標,如果不能達到 DB2 要求數(shù)量,則 DB2 無法正常工作,其具體數(shù)字不易記憶,但可以查看 db2diag.log,里面記錄了 DB2 所需要的具體數(shù)字,依照該數(shù)字更新內(nèi)核參數(shù)即可。
DB2 Runtime Client 可否不安裝開發(fā)工具包,只安裝足夠客戶端工作的組件,以方便模擬客戶實際應用環(huán)境進行測試?
解決辦法:DB2 Runtime Client并不包含開發(fā)工具包。其功能就是只提供客戶端工作的組件包。
一個裸設備無法同時分配給兩個數(shù)據(jù)庫,這樣無法建立兩個數(shù)據(jù)庫服務器共享同一個裸設備
解決辦法:把這兩個數(shù)據(jù)庫分別建在不同的實例上,將其中一個實例停下,第二個實例啟動,分配裸設備給該活動實例上的數(shù)據(jù)庫,分配完畢后將活動實例停下,啟動第一個實例,重復先前分配裸設備的操作到第一個實例,即可實現(xiàn)當一個數(shù)據(jù)庫停下時,該裸設備數(shù)據(jù)可以完全被另外一個數(shù)據(jù)庫接管,從而實現(xiàn)共享。
原因分析:一個容器是無法同時分配給兩個活動數(shù)據(jù)庫的。必須針對兩個實例來操作,分配給一個實例時另一個實例必須處于不活動狀態(tài)。
在 Linux 上 DB2 安裝完成后,不能綁定 License,報 DBI1430N 錯誤
解決辦法:
1.更新系統(tǒng)時間到當前時間。使用 Linux 中的 DATE 命令;
2.使用 db2licm 命令綁定 License:
清單 2. 綁定 License 命令示例
./db2licm -a db2ese.lic
在Linux 上 DB2 實例創(chuàng)建不成功,返回錯誤碼 DBI1281E
解決辦法:正確設置主機名;
原因分析:DB2 創(chuàng)建實例時要取主機名,如果主機名設置不正確,則會報告無法初始化實例的錯誤,也就是 DBI1281E,可以首先用 uname 或者 hostname 查看是否有主機名,進一步可以用 ping 命令驗證主機名是否正確,如果 ping 不通則不正確,還可以檢查 /etc/hosts 查看 IP 和主機名的對應關(guān)系是否正確。
#p#
連接數(shù)據(jù)庫
SuSE Linux C shell 環(huán)境下,無法連接數(shù)據(jù)庫
解決辦法:在cshell下,執(zhí)行以下腳本設置環(huán)境,或?qū)⒃撁罴拥?Linux 用戶配置文件中:
清單3. 設置環(huán)境
source /sqllib/db2csrhc
原因分析:在 Linux 下,根據(jù)不同的 shell,需要執(zhí)行不同的腳本來設置環(huán)境。
清單 4. 在不同的 shell 環(huán)境下設置
. /sqllib/db2profile (B shell 或 K shell)
source /sqllib/db2csrhc (C shell)
CLP 連接數(shù)據(jù)庫服務器返回錯誤,提示 codepage 無法轉(zhuǎn)換,按提示更改代碼頁后仍然無法連接
解決辦法:在 CLP 中運行 db2 terminate 后再重新連接即可;
原因分析:在 CLP 中 codepage 更改不會即時生效,必須斷掉當前連接再連才會生效。
Solaris 5.8 下用命令行方式無法連接數(shù)據(jù)庫,提示遇到錯誤 SQL1084C
解決辦法:編輯 /etc/system 調(diào)整內(nèi)核參數(shù),重啟機器;
原因分析:查看 db2diag.log 可以發(fā)現(xiàn)消息隊列錯誤,進一步發(fā)現(xiàn)該機器上的內(nèi)核參數(shù)的消息隊列值被改為 4096,DB2 需要 65535,更改這個參數(shù)重啟機器和數(shù)據(jù)庫,再連成功。
在Linux C Shell下創(chuàng)建新的 DB2 用戶之后,用該用戶無法連接數(shù)據(jù)庫
解決辦法:在該用戶 home 目錄下尋找 .cshrc 文件,如果沒有則手工創(chuàng)建一個,然后在該文件中加入以下一行,然后重新登陸或者使用 source .cshrc 即可連接數(shù)據(jù)庫。
清單5. shell 環(huán)境設置
source /sqllib/db2cshrc
原因分析:創(chuàng)建的用戶所用的 shell 是 C shell,調(diào)用的是 .cshrc,該文件不存在,手工創(chuàng)建該文件,并在該文件中調(diào)用 sqllib/db2cshrc 后即可以正常連接數(shù)據(jù)庫。
#p#
存儲過程
在Stored Procedure 中如何判斷一個系統(tǒng)文件是否存在
解決辦法:使用 Java 開發(fā)一個 UDF, 將文件全名通過參數(shù)傳遞給這個 UDF,在 UDF 中判斷系統(tǒng)文件是否存在然后返回結(jié)果代碼;
原因分析:存儲過程的主要目標是對數(shù)據(jù)庫對象的操作,對文件系統(tǒng)操作需要借助于外部語言開發(fā)用戶自定義函數(shù),DB2 中提供了用各種外部語言開發(fā)函數(shù)的機制,所以推薦用 Java 開發(fā) UDF 后,由該存儲過程來調(diào)用。
DB2 SQL PL 的 HANDLER FOR SQLEXCEPTION, SQLWARNING, NOT FOUND 無法捕獲 SQLCODE=-727 和 SQLCODE=-911 的異常
解決辦法:將 DB2 補丁升級到 DB2V8 FixPack9;
原因分析:在 DB2 V8 FixPack7 上的確存在該問題,在 FixPack9 中已經(jīng)解決。
備份與恢復
DB2中可否查詢最近一次全備份執(zhí)行的時間以及全備份文件存放的路徑
解決辦法:在 CLP 中可以使用 list history backup all for 命令查看,如需要在存儲過程中使用,可使用表函數(shù)查詢:
select from table(snapshot_database('sample',-2)) as t
原因分析:snapshot_database() 是 DB2 中提供的表函數(shù),可以返回當前數(shù)據(jù)庫的一些信息,其中包括了數(shù)據(jù)庫上次備份的時間信息。第一個參數(shù)是數(shù)據(jù)庫名,第二個參數(shù)是數(shù)據(jù)庫分區(qū)標志,-2 代表所有分區(qū),-1 代表當前分區(qū)。
如何在數(shù)據(jù)庫恢復的時候重定向表空間
解決辦法:使用如下命令,詳情請參見《DB2備份和恢復》簡明手冊:
清單6. 在數(shù)據(jù)庫恢復的時候重定向表空間
RESTORE DATABASE SAMPLE FROM \"C:\TEMP\" TAKEN AT 20050626155952 REDIRECT;
SET TABLESPACE CONTAINERS FOR 0 IGNORE ROLLFORWARD CONTAINER OPERATIONS
USING (PATH \"C:\DB2\NODE0000\SQL00005\SQLT0000.0\");
RESTORE DATABASE SAMPLE CONTINUE;
#p#
數(shù)據(jù)操作
如何對應 SQLServer 的 InsertBulk 命令?
解決辦法:使用 load 命令。
如何給 VARGRAPHIC 類型字段設置缺省值?
解決辦法:將數(shù)據(jù)庫建為 UTF-8 格式的數(shù)據(jù)庫。
表中有 long varchar 字段,在存儲過程的游標中,以 select distinct varchar(該字段)……方式選擇記錄,但編譯通不過
解決辦法:把 distinct 去掉;
原因分析:如果有 long 型字段,加 distinct 關(guān)鍵字就失去意義而且十分影響性能,另外該列在原來的 Oracle 應用中也只是定義為 varchar(4000),建議在 DB2 中仍設為 varchar 型,同時將該表所在表空間的 pagesize 加大,由缺省的 4k 設為 16k 或 32k。
DB2存儲過程中的異常處理如何寫,與Oracle中的有何區(qū)別?
解決辦法: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;
如何查詢數(shù)據(jù)庫中用戶已定義的表?
解決辦法:select * from syscat.tables;
原因分析:DB2 提供了一組視圖用以用戶查詢數(shù)據(jù)庫對象,這些視圖統(tǒng)一存放在 SYSCAT 模式下,這些視圖幾乎包含了所以的數(shù)據(jù)庫對象編目信息,包括表、視圖、名字空間、存儲過程等等。用戶可以在《DB2 UDB SQL Reference Volume 1》SQL Reference 1 的 Appendix D 中找到這些視圖的詳細定義。
如何查詢數(shù)據(jù)庫中用戶已定義的 sequence?
解決辦法:使用 select * from syscat.sequences。
如何用SQL語句獲得表空間的當前使用率?
解決辦法:可以使用如下 SQL 語句查詢,在用該語句獲得了表空間已用頁數(shù),可用頁數(shù)等信息后,即可計算出表空間當前使用率:
清單9. 獲得表空間頁數(shù)信息
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 中可以將游標結(jié)果集通過 BULK 方式存入宿主數(shù)組中,DB2中如何實現(xiàn)?
解決辦法:DB2 中不支持 BULK 方式,其替代方式是定義相應的數(shù)組,然后以循環(huán)方式每次從游標結(jié)果集中 fetch 一條記錄到數(shù)組元素中。
DB2中如何用 SQL 語句取出滿足條件的結(jié)果集的前N條記錄?
解決辦法:使用 select * from where fetch first row only
Oracle中有 trunacte 表的功能,速度非???,它只是把表標志設為空,并不發(fā)生刪除數(shù)據(jù)的 IO 操作,DB2 中如何做類似操作?
解決辦法:可以先 drop 表,再重建該表
原因分析:Oracle 中 trunacte 表的速度之所以快,是因為它不記日志,只是直接把表的結(jié)構(gòu)信息刪除了,并不發(fā)生刪除數(shù)據(jù)的 IO 操作。DB2 中 drop 表,也不會引起數(shù)據(jù) IO 和日志記錄,從而達到相同的效果。但前提是你預先有創(chuàng)建表的結(jié)構(gòu)。否則不要隨意 drop 表。
Oracle 有 truncate,DB2 中建議使用 drop,然后再 create 表,這樣好還是 alter 表好?
解決辦法:Oracle 的 truncate 是直接把表的數(shù)據(jù)清空,但不記日志,所以速度很快。DB2 中 drop 表也避免了大量記錄記入日志的問題,再重建表就達到了快速清空表的目的。但 alter 是用于修改表結(jié)構(gòu)的,和表的數(shù)據(jù)操作沒有關(guān)系。
#p#
在一次性導入大量數(shù)據(jù)到表中時,會因為寫日志而影響性能,如何提高該操作的性能,在導入數(shù)據(jù)后,需要做更新統(tǒng)計操作,如何做?
解決辦法:一次性導入大量數(shù)據(jù)時為了提高性能,可以使用 alter table activate not logged initially 在該事務中關(guān)閉該表的日志選項,然后執(zhí)行數(shù)據(jù)導入,在該事務結(jié)束后,該表日志開關(guān)自動打開。在導入大量數(shù)據(jù)后,為了提高查詢性能,再運行 runstats on table 命令更新查詢統(tǒng)計信息。
提示:必須在一個事務中執(zhí)行關(guān)閉日志和數(shù)據(jù)導入才會不記日志,當前事務結(jié)束后日志開關(guān)會自動重新打開。
DB2 中如何定時執(zhí)行一些任務,如表的清空等維護操作?
解決辦法:在任務中心圖形界面中將維護腳本導入,并設定定時調(diào)度的時間周期,任務中心會自動調(diào)度該任務。運行任務中心的前提是數(shù)據(jù)庫服務器上已裝有任務中心,并已編目工具目錄數(shù)據(jù)庫,如果沒有工具目錄數(shù)據(jù)庫,請按以下步驟操作:
a.使用 create db taskdb 創(chuàng)建一個新的數(shù)據(jù)庫,以用于工具目錄數(shù)據(jù)庫;
b.使用 db2admin start 啟動數(shù)據(jù)庫管理服務器,如果已經(jīng)啟動,進入第三步;
c.使用 db2 create tools catalog toolscat use existing db taskdb 編目工具目錄數(shù)據(jù)庫。
DB2 中如何實現(xiàn)為一個 DMS 表空間自動添加容器的腳本?
解決辦法:可以先計算表空間當前可用大小,如小于某個設定值,則用 Alter tablespace add (...) 語句添加新的容器到表空間。計算表空間可用大小的方法可以參照問題“如何用sql語句獲取表空間的當前使用率?”
用 UDF 實現(xiàn)了將 TimeStamp 類型的一個變量轉(zhuǎn)換成 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,實現(xiàn)了將 timestamp 轉(zhuǎn)換為 date 的功能,其結(jié)果通過 with 語句被定義為一個 t1 中的虛列 col1,然后在 t1 中按 col1 分組。注意上面是一條語句,中間沒有分隔符。
如何做類型轉(zhuǎn)換才能將 VARGRAPHIC 類型的數(shù)據(jù)用在 LOCATE 函數(shù)中?
解決辦法:先將 VARGRAPHIC 轉(zhuǎn)換成 VARCHAR。然后再用于 locate 函數(shù)。
原因分析:LOCATE 函數(shù)只能接受字符串作為輸入,所以必須將 VARGRAPHIC 先轉(zhuǎn)換成 VARCHAR。同時在數(shù)據(jù)庫編碼格式上有要求,只有用 Unicode codepage 創(chuàng)建的數(shù)據(jù)庫才能實現(xiàn) VARGRAPHIC 到 VARCHAR 的轉(zhuǎn)換。所以之前要用 UTF-8 CN_ZH 方式創(chuàng)建數(shù)據(jù)庫。
如何使用 DB2 JDBC TYPE 4 方式連接數(shù)據(jù)庫?
解決辦法:將 JDBC Driver 配置為 com.ibm.db2.jcc.DB2Driver,在程序中數(shù)據(jù)庫 URL 指定為 jdbc:db2://server:port/alias。Server 是指數(shù)據(jù)庫服務器所在主機名或 IP;port 是數(shù)據(jù)庫服務端口號,缺省是 50000;alias 是數(shù)據(jù)庫別名。編譯時需要 db2jcc.jar,記得把它指定在 classpath 中。
如何將一個 timestamp 類型轉(zhuǎn)換為 yyyymmdd 格式?
解決辦法:可以使用用戶自定義函數(shù)(UDF)來實現(xiàn)。以下是一個廣為流傳的轉(zhuǎn)換函數(shù)代碼:
清單10. 將 timestamp 類型轉(zhuǎn)換為 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 中,使用以下命令創(chuàng)建函數(shù):db2 –td@ -f func.db2。然后即可使用該 UDF 進行時間格式轉(zhuǎn)換。該函數(shù)可以根據(jù)輸入的 timestamp 轉(zhuǎn)換為多種格式,包括 yyyymmdd,mm/dd/yyyy,yyyy/dd/mm hh:mi:ss,或者返回毫秒數(shù)(nnnnnn)。
在 SQL 存儲過程中有('每月'||COALESCE(VAR, '')||'元')語句時,編譯無法通過
解決辦法:客戶端 codepage 和腳本的編碼格式不同,所以服務器端無法識別腳本命令,把客戶端 codepage 設為 1386 即可。
Oracle 中有一個函數(shù) DBMS_SQL.VARCHAR2_TABLE,可以傳入一個以某個分隔符為分隔的字符串,該函數(shù)將該字符串以分隔符拆分,返回給調(diào)用者一個數(shù)組或是表,DB2 中如何實現(xiàn)類似功能?
解決辦法:用全局臨時表實現(xiàn);
原因分析:Oracle 中的 varchar2_table 其實是集合的概念,在 DB2 中不支持集合。DB2 通常做法是聲明全局臨時表(DGTT),第一列存儲記錄順序,第二列存儲數(shù)據(jù)。以下是示例,在聲明后即可向該表中插入和查詢數(shù)據(jù),效果和集合相同。
清單 11. 實現(xiàn)拆分
DECLARE GLOBAL TEMPORARY TABLE SESSION.temp_emp_list
(num integer, EmpName varchar(30))
WITH REPLACE
ON COMMIT PRESERVE ROWS NOT LOGGED;
DB2 無法對允許空值的列建唯一性索引
解決辦法:將該列屬性設為不允許為空;
原因分析:空值在數(shù)據(jù)庫中被認為是不確定值,任何其他值與空值組合,結(jié)果仍然是空值,不具備唯一性,所以 DB2 不允許空值列作為唯一鍵的索引列。
同一張表的索引可以放在不同表空間中嗎?
解決辦法:在創(chuàng)建表的時候使用 INDEX in tablespace-name 選項,在該表上創(chuàng)建的索引將存放在指定的表空間上;
原因分析:表數(shù)據(jù),表索引,以及表中的 long 型數(shù)據(jù)可以分開存放在不同的表空間。可以提高性能。
用UDF 調(diào)用存儲過程總是編譯通不過,報關(guān)鍵字沖突錯誤
解決辦法:把該 UDF 改造成存儲過程;
原因分析:DB2 中 UDF 主要用于邏輯運算和處理,存儲過程則偏重于處理數(shù)據(jù)庫對象,如表數(shù)據(jù)的增刪查改,所以兩者的用途不同決定了其使用方式也不同,UDF 使用的是內(nèi)嵌的 SQL 語句,是 SQL 語言的子集,不能執(zhí)行動態(tài) SQL,如果 UDF 調(diào)用存儲過程,則會導致 SQL 嵌套上的混亂,因為 UDF 通過調(diào)用存儲過程實現(xiàn)了 SQL 全集,這是不允許的,所以報關(guān)鍵字沖突,把該 UDF 改為存儲過程即可。
建議對于不涉及數(shù)據(jù)庫表操作的業(yè)務邏輯可以用 UDF 實現(xiàn),如邏輯算法,文件操作,系統(tǒng)調(diào)用等,而涉及到數(shù)據(jù)庫表操作的功能則交給存儲過程來實現(xiàn)。存儲過程可以調(diào)用 UDF。
工具使用
如何在 CLP 中查看表結(jié)構(gòu)
解決辦法:使用 db2 describe table 命令。
用開發(fā)中心遠程調(diào)試存儲過程,可以構(gòu)建,但構(gòu)建并調(diào)試卻不能成功
解決辦法:在遠程數(shù)據(jù)庫上安裝 DB2 開發(fā)包;
原因分析:在遠程調(diào)試時將會調(diào)用遠程數(shù)據(jù)庫上的開發(fā)包,所以遠程服務器一定要裝有開發(fā)包才可遠程調(diào)試。
如何將部署在 DB2 數(shù)據(jù)庫上的存儲過程導出為可執(zhí)行腳本,以便在其它機器上部署
解決辦法:在開發(fā)中心中可以導出存儲過程為腳本,前提是之前創(chuàng)建存儲過程的時候沒有指定 hide body。
如何讓 DB2 自動運行 runstat
解決辦法:使用 db2 update db cfg using auto_runstats on 命令。
【編輯推薦】