引言
Oracle以其優越的穩定性和卓越的效能在眾多領域裡有著廣泛的應用,其高效能是Oracle優於其他資料庫的關鍵因素。然而影響終端應用程式的效能不只是Oracle服務程式及硬體環境,應用程式的開發語言和開發方式也有著重要的影響。
目前,可以在多種開發語言中開發Oracle應用程式,比如可以在VB、Delphi等進階開發語言中開發,可以以C++開發,也可以以Java語言開發,甚至可以通過ASP、JSP、Perl等指令碼語言來訪問Oracle。這些語言環境各有其優勢,C++無疑是追求極致速度的首選。
在C++中我們也可以有多種介面方式,可以使用ADO通用介面,可以使用OCI/OCCI,還可以使用ODBC、OO4O及OLEDB等方式。在這些方式中,ADO與OCI是應用最為廣泛的兩種方式,本文將集中力量介紹在Visual C++ 6.0 中這兩種介面的開發方法及它們的特點對比。
一 ADO開發介面簡介
ADO(ActiveX Data Objects,ActiveX資料對象)是Microsoft為強大的資料提供者 OLEDB(物件連結與嵌入資料庫)而設計的,是一個便於使用的應用程式層的編程介面。使用 ADO編寫的應用程式可以通過OLEDB提供者訪問和操作資料庫伺服器中的資料。ADO 最主要的優點是便於使用、可以訪問多種資料庫及可以在多種語言中開發。
由於ADO建立在自動化(Automation)的基礎上,所以ADO的應用場合非常廣泛,不僅可在Visual Basic這樣的進階語言開發環境中使用,還可以在一些指令碼語言中使用,這對於開發Web應用和在ASP(Active Server Page,動態伺服器首頁)的指令碼代碼中訪問資料庫提供了操作應用的捷徑。
ADO訪問資料庫的模型示意參見圖1。
圖1 ADO模型
從可以看出ADO是以OLE DB為基礎,它對OLE DB進行了封裝,所以ADO其實是OLE DB的應用程式層介面,是介於OLE DB與應用程式之間的中介層。這種結構為一致的資料提供者提供了很好的擴充性,不再局限於特定的資料來源,只要OLE DB支援的資料來源,ADO都可以很好地支援。
ADO的另一個特性是使用簡單,它封裝了OLE DB的複雜的介面,以Connection、Recordset、Command三個主體對象及Errors、Properties、Parameters和Fields四個集合對象搭建起了ADO物件模型,見:
圖2 ADO物件模型
通過這七個對象及它們的方法,我們就可以完成絕大多數的訪問資料庫的任務,來實現我們的應用目標。
二 OCI開發介面簡介
OCI(Oracle Call Interface)是Oracle 資料庫調用介面,是由Oracle提供的用於開發前端應用程式及中介軟體的C/C++開發類庫。通過OCI,可以控制所有類型的SQL語句的執行,包括DDL、控制語句(事務、會話、系統)、查詢、DML、PL/SQL,以及嵌入式SQL。OCI能夠最大程度地控製程序的運行,執行Oracle伺服器所允許的多有資料庫操作,可以訪問Oracle資料庫伺服器裡的所有資料類型,包括標量值、集合和所有物件類型的執行個體,可以以引用的方式訪問對象及其中繼資料,可以動態擷取、修改對象的屬性值。
OCI程式既具有SQL非過程性的優點,也具有第三代程式設計語言的過程性和靈活性,使開發的編程技術具有更強的資料處理能力。
同時,OCI在所有運行Oracle的平台上具有良好的可移植性,程式無須太大修改即可運行在Unix/Linux/Windows甚至嵌入式環境下。
OCI還是其他Oracle開發介面的底層實現,如ADO、JDBC都是在OCI上層的封裝,由於OCI是比較底層的介面,少了很多層的封裝,可以提供應用程式與Oracle的直接連接,所以OCI可以提供最佳的效能。正是基於此,Oracle自身的一些工具及許多著名的Oracle 資料庫工具也都是用OCI開發的,如大名鼎鼎的Toad。筆者的OraExplorer也是基於OCI介面開發。
但由於C/C++的學習難度比較大,所以OCI的開發難度與ADO、JDBC等開發介面相比要大許多,OCI的每一個函數的參數都非常多,且比較難以理解,而國內關於OCI開發的學習資料非常少,所以使用OCI開發應用程式的程式員相對ADO的程式員要少得多。
三 對比實驗設計
本文將通過一個具體的實驗來對比ADO與OCI的效能差距,資料庫提供者的效能主要體現在兩個方面,一個是資料讀取速度,另一個是資料寫入速度,所以本文將基於ADO和OCI各自開發一個Visual C++ 6.0應用程式來進行這兩個方面的實驗,每個程式完成功能如下:
1) 建立串連
首先,需要串連到Oracle伺服器,在這一步需要使用者提供SID、使用者名稱和密碼資訊。
2) 資料初始化
為了實驗的通用性及方便讀者重現,本實驗直接在System使用者下操作,需要一個記錄數比較多的表來,首先對all_objects表鏡像,產生my_objects表,然後對My_objects表自身進行五次遞迴鏡像,最產生一個百萬記錄的表。相關SQL語句如下:
Truncate table my_objects; Drop table my_objects; create table my_objects as select * from all_objects; insert into my_objects select * from my_objects; insert into my_objects select * from my_objects; insert into my_objects select * from my_objects; insert into my_objects select * from my_objects; insert into my_objects select * from my_objects; |
3) 資料讀取
遍曆資料表,讀取Object_name欄位的值,並記錄花費的時間。
4) 資料寫入
--建立新表 truncate table my_objects2; drop table my_objects2; create table my_objects2 ( owner varchar2(30), object_name varchar2(30), subobject_name varchar2(30), object_id int, data_object_id int); |
向表中寫入10萬條記錄,並記錄花費的時間。
5) 清空環境
釋放記憶體,中斷連線。
四 ADO程式關鍵代碼
首先需要在stdafx.h中添加如下代碼
//消除一些無用的警告 #pragma warning(disable:4146 4244) //匯入ADO應用庫,並對命名空間及EOF重新命名 #import "C:\Program Files\Common Files\System\ADO\msado15.dll" \ rename_namespace("MYADO") rename("EOF", "EndOfFile") 下面的是關鍵實現代碼: //初始化連線物件 hr = m_pConnection.CreateInstance(__uuidof(MYADO::Connection)); //初始化記錄集對象 m_pRs.CreateInstance(__uuidof(MYADO::Recordset)); //設定串連參數 CString strConnection; strConnection.Format(_T("Provider=OraOLEDB.Oracle.1;" "Password=%s;" "User ID=%s;" "Data Source=%s"), strPwd, strUser, strSID); //串連到資料庫 m_pConnection->Open((_bstr_t)strConnection,_T(""),_T(""),-1); //執行SQL語句 strSQL.Format("Truncate table my_objects"); m_pConnection->Execute(_bstr_t(strSQL),NULL,MYADO::adCmdText); //開啟記錄集 strSQL.Format("Select object_name from my_objects"); m_pRs->Open((_bstr_t)strSQL, m_pConnection.GetInterfacePtr(), MYADO::adOpenForwardOnly, MYADO::adLockReadOnly, MYADO::adCmdText); //遍曆並讀取資料 while(!m_pRs->EndOfFile) { varValue = m_pRs->Fields->GetItem(long(0))->GetValue(); m_pRs->MoveNext(); } strSQL.Format("Insert into my_objects2 values ('TestTest','TestTest','TestTest',0,0)"); //寫入資料 for(int i=0;i<100000;i++) { m_pConnection->Execute( _bstr_t(strSQL),NULL,MYADO::adCmdText); } //關閉串連 m_pConnection->Close(); |
OCI的關鍵代碼限於篇幅,不予羅列。
本實驗的ADO應用程式的原始碼、可執行程式以及OCI的可執行程式可以到http://www.snowywolf.net下載,OCI的原始碼因涉及技術保密問題,無法公開,敬請諒解。
五.實驗結果
為了消除網路影響,Oracle伺服器和應用程式在同一台筆記本上運行。
- 硬體環境
- CPU:Intel 雙核2.0G
- 硬碟:7200轉 100G
- 記憶體:1G
- 軟體環境
- 作業系統:winXP SP2
- 資料庫:Oracle 9.2.0.1.0
統計結果中的程式碼數為除去介面通用代碼後的有效程式碼數。
六.ADO與OCI對比分析
1.功能方面
ADO為了保持其通用性,除了對MS SQLServer支援較好外,沒有辦法對其他資料庫提供很完善的功能,對Oracle同樣如此。通過ADO訪問Oracle,可以實現比較通用的功能,如DML、DDL、查詢、事務控制等,但對於Oracle中的對象、集合、LOB等特殊元素則不能很好地支援,對於PL/SQL的支援也很不完整。而OCI在這方面則有著顯著的優勢,它可以很完整地支援Oracle的所有功能,可以說是對Oracle功能支援最完整的開發介面。而且OCI可以支援多種作業系統,而ADO則只能在Windows系列作業系統下運行。
但在支援面方面,ADO則有很大優勢:一方面,它幾乎支援目前所有流行的資料庫,如MS SQLServer、Oracle、Sybase、DB II等,寫好的訪問一種資料庫的代碼,可以稍做修改就能支援另一種資料庫,這是ADO的巨大優勢;另一方面,它也幾乎支援目前所有的開發環境,不管是採用VC開發還是用VB開發,甚至採用Delphi、ASP等等都可以使用ADO來訪問資料庫。
2.效能方面
從上面的實驗結果可以看出,在效能方面,OCI也有著非常大的優勢,讀取資料的速度快了4倍多,寫入資料的速度快了一百多倍。
由於OCI省掉了應用程式與Oracle伺服器之間的中間封裝層,可以直接存取資料,另外,OCI是C介面,可以直接操縱內在,所以其訪問速度非常快,佔用系統資源和網路資源也都要少得多。
在筆者的開發經驗中,對於儲存在Oracle中的位元據(如空間資料、影像資料)及長字串資料,OCI的效能優勢要更加明顯.。
3.開發難度方面
在這方面ADO的優勢很明顯,首先,ADO的學習難度較低,ADO是以物件導向的思想封裝的,其對象和方法都易學易用,而且ADO的學習資料很豐富,網上可以找到大量的文檔及原始碼;而OCI則是過程化封裝的開發介面,它的函數雖然不是很多,但函數之間的關係比較複雜,且函數的參數非常多,很多函數都有十幾個參數,非常難於理解。另外,國內使用OCI開發的程式員比較少,可用的參考資料也非常少,所以OCI的學習難度很大。
另一方面,OCI開發的程式的代碼量要比ADO的多得多,且代碼之間的關係比較複雜,不易維護。
為瞭解決這一方面的問題,筆者基於OCI進行了基於物件導向思想的封裝,簡化了OCI 的開發模型,並封閉了OCI的異常處理機制,使得OCI的開發難度大大降低,代碼量能夠接近於ADO的代碼量,且更易維護。這一部分的內容不屬於本文討論範圍,所以不在此展開論述。
七.總結與結論
ADO與OCI是在VC中開發Oracle應用程式的常用的兩種介面,它們各自有著自己的特點,有獨特的優勢,也都有自己的局限性,在開發過程中我們需要根據具體情況來選擇使用哪種開發介面。
如果應用程式需要訪問多種資料庫,既要訪問儲存在Oracle中的資料,也要訪問儲存在MS SQL Server中的資料,那麼ADO是最佳選擇,它可以使用一套代碼實現多種資料庫的訪問。
如果應用程式只需要訪問Oracle資料庫,且對效能要求很高,那OCI就是最好的選擇了。