本節介紹根據各種類型的應用程序選擇A P I的方法,比較C、DBI 和PHP API 的能力,並給出它們相對的優點和缺點,並指出什麼時候應選擇哪一個。
首先應該指出,筆者不認為任一種語言優於其他語言。盡管筆者的確有自己的喜好,但還是統統使用它們。您也會有自己的喜好,像我的評論家一樣。一個評論家會感覺應該強調C 對MySQL編程的重要性,應將這種重要性上升到更重要的程度,而另一個評論家會認為C編程相當困難,應放棄使用它!您應當權衡本節中討論的這些因素,得出自己的結論。在對特定任務選擇哪個API 時,要考慮以下問題:
■ 預期的執行環境。期望使用應用程序的上下文環境。
■ 性能。當在API 語言中編寫時,如何使應用程序高效地執行。
■ 開發的容易性。如何便於API 和它的語言編寫應用程序。
■ 可移植性。除MySQL以外,應用程序是否還將用於其他數據庫系統。
下面進一步分析每個問題。要注意這些因素的相互影響。例如,您想要一個運行良好的應用程序,但使用一個可快速開發該應用程序的語言也同等重要,即使該應用程序不能非常有效地運行也同樣。
5.2.1執行環境
當編寫應用程序時,通常應考慮使用哪種環境。例如,該應用程序可能是從外殼程序中調用的報告生成器程序,或一個應付賬目概要程序,在每月的月底作為cron job 進行運行。從外殼程序或cron 程序中運行的命令通常依賴它們自己,而且很少需要運行環境。另外,可以編寫一個應用程序來試圖由Web 服務器調用。這樣的程序期望能從它的運行環境中抽出非常特殊類型的信息:客戶正在使用什麼浏覽器?在郵件清單訂閱請求格式中輸入什麼參數?客戶提供正確的口令訪問我們個人信息了嗎?每種API 語言都以它在這些不同的環境中適於編寫應用程序而變化:
■C 是通用目標的語言,從理論上講任何任務都可使用它。在實際中, C 傾向於用於更頻繁的獨立程序而不是對Web 的編程。其原因可能是在C 中不像在Perl 或在PHP 中那樣容易地實現文本處理和內存管理,並且這些處理和管理在Web 應用程序中大量地使用。
■ Perl,像C 一樣,適合於編寫獨立的程序。然而,對於Web 站點的開發,Perl 也是非常有用的,例如通過使用CGI.pm 模塊。這使Perl 成為編寫連接MySQL和Web 的應用程序的便利的語言。這樣的應用程序可以經CGI.pm 模塊與Web 接口,並可以使用DBI 與MySQL相互作用。
■ PHP 是設計用來編寫Web 應用程序的語言,所以這個環境顯然是最適合的。而且,數據庫訪問是PHP 最大的優勢之一,所以它是實現與MySQL相關的任務的Web 應用程序最自然的選擇。也可以將PHP 作為一個獨立的解釋程序(例如,從外殼程序中運行腳本),但不能非常頻繁地使用它。
根據以上這些需要考慮的問題,對於獨立的應用程序, C 和Perl 是最佳語言。對於We b應用程序, Perl 和PHP 是最合適的。如果需要編寫這兩種類型的應用程序,但又不會使用這些語言的任何一種,並想用盡可能少的精力來學習,則Perl 可能是您最佳的選擇。
5.2.2 性能
我們通常喜歡應用程序盡可能快地運行。然而,實際上性能的重要性取決於所使用的程序的頻率。對於一個月運行一次晚上定時工作的程序,性能可能不是非常重要的。而對於在Web 站點上一秒鐘運行若干次的程序,則每當排除一點無效性都會帶來巨大的不同。後一種情況下,在站點的有效性和請求中,性能發揮著重要的作用。一個緩慢的站點是令用戶苦惱的,無論站點的內容如何,如果您依靠站點作為一項收入來源,則性能的降低直接影響收入。如果不能一次為多個連接提供服務,訪問者只會產生厭煩情緒而去其他的站點。
性能評價是一個復雜的問題。當編寫特定的API 時,應用程序完成得好壞的最好指標是在這個API 環境下編寫並進行測試。而且最好的比較測試是在不同的API 環境下多次運行該應用程序,來比較每個版本。當然,那不是一般的工作。一般來說,您只想獲取編寫的應用
程序。一旦它工作了,如果它需要運行得更快,您就可以考慮優化它,使用更少的內存,或有某些需要用其他方法提高的方面。但是,至少有如下兩個因素會影響性能:
■ 編譯的程序比解釋的程序運行得更快。
■ 對於在Web 上下文環境中使用的解釋語言,在解釋程序作為We b服務器自身的一部分而不是單獨的過程模塊被調用時,性能更好。
1. 相對於解釋語言的編譯語言
編譯的應用程序比用腳本語言編寫的程序的同樣版本效率更高、使用的內存更少,並且執行得更快,這是基本規律。這是由於執行腳本的語言的解釋程序的開銷問題。因為C 是編譯的,而Perl 和PHP 是解釋的,所以C 程序通常比Perl 或PHP 腳本運行得更快一些。對於大量使用的程序,通常用C 是最好的選擇。在MySQL分發包中包括的MySQL命令行客戶機程序就是最好的樣例。
當然,有一些因素能使這種明顯的差別減小。對於一項任務,可用C 編寫出更快的程序,但也很有可能編寫出低效率的C 程序。用編譯語言編寫的程序並不自動地保證更好的性能。所以需要不斷地考慮所做的事情。此外,如果一個腳本化的應用程序需花費大部分時間來執行連接到解釋程序引擎的MySQL客戶機庫例程的代碼,則編譯程序和解釋程序之間的差別將有所減少。
2. 相對於語言解釋程序模塊版本的獨立程序
對於基於Web 的應用程序,腳本語言解釋程序通常以兩種形式之一來使用,至少對Apache 是這樣,當編寫Web 應用程序時,apache 是我們將使用的Web 服務器:
■ 可以安排Apache 去調用這個解釋程序作為單獨的過程。當apache 需要運行Perl 或PHP 腳本時,它啟動相應的程序,並告知它來執行該腳本。在這種情況下, apache 使用該解釋程序作為CGI 程序,也就是說,它使用公共網關接口( Common Gateway Inter face,CGI)協議與它們通信。
■ 解釋程序可用作直接連接到Apache 二進制程序和作為其過程自身的一部分運行的模塊。在apache 條件下, Perl 和PHP 解釋程序獲得mod_perl 和mod_PHP3 模塊的形式。
Perl 和PHP 的提倡者們極力宣揚解釋程序有速度優勢,但所有的人都同意之所以喜歡解釋程序是因為其運行的形式比語言本身有更大的誘惑力。在這兩者中,解釋程序作為模塊運行比作為獨立的CGI 應用程序運行更快。
對於獨立的應用程序,每當運行一個腳本時都必須啟動該解釋程序,所以將導致重大的創建過程的開銷。當在已經運行apache 過程的內部作為模塊使用時,解釋程序可以立即從Web 頁面中訪問。通過減少開銷顯著地提高了性能,並直接轉換為快速處理獲取的請求並發送它們的能力的增加。
獨立解釋程序啟動的性能比模塊解釋程序的性能至少差一個數量級。當考慮Web 頁面服務包括少量處理的快速事務處理而不是具有許多處理時,解釋程序啟動的開銷特別重要。如果花費許多時間只是為了啟動而不是用於實際執行該腳本,則大部分資源一直處於等待狀態。一天中的大部分時間可能花費在准備工作上, 4 點到達,然後5 點回家。
您可能想知道,為什麼解釋程序的模塊版本由於必須一直啟動Apache 而能節省時間呢?。這個原因是,當Apache 啟動時,它立即產生一些子過程,用於處理收到的請求。當包括腳本執行的請求到達時,已經有Apache 進程在准備等待去處理它。同樣, apache 的每個實例可服務於多個請求,所以該進程啟動的開銷只導致每組請求一次,而不是每個請求一次。
當Perl 和PHP 以模塊形式安裝時(像mod_perl 和m o d _ p h p 3),哪一個完成得更好一些?那就是爭論的主題,以下是適用於一般性的指南:
■ Perl 將腳本轉換為內部可編譯的形式;而PHP 卻不這樣。因此,一旦該腳本通過語法分析,則Perl 可更快地執行它,特別是對於具有大量迭代的循環。
■ mod_perl 可以運行腳本高速緩存來提高重復執行的腳本的性能。如果腳本在高速緩存中,則Perl 可更快地開始執行腳本,因為它不需要再一次分析。否則, PHP 開始執行的該腳本的速度更快。
■ mod_perl 比PHP 有更大的內存覆蓋區;利用mod_perl 連接的apache 進程比利用mod_php3 的更大。PHP 被假定必須在另一個進程的內部協同存在,並且在那個進程內部可以多次激活或撤消。Perl 被設計成從命令行作為獨立程序運行,而不是作為被嵌入在Web 服務器進程中的一個語言進行運行。這可能使它付出較大的內存覆蓋區;
Perl是模塊,因此它不運行在自身環境中。腳本的高速緩存和該腳本使用的附加Perl模塊是付出較大的內存覆蓋區的另外的因素。在這兩種情況下,有更多的代碼使用內存,並將運行的apache 進程保留在內存中。
在腳本運行速度方面,Perl 無論有什麼可超過PHP 的優勢,都被PHP 4 除掉了。PHP 4 在它的能力和接口方面類似於PHP 3,但它合並了Zend,Zend 是一種更高性能的解釋程序的引擎。
無論如何,所有的這些因素只導致Perl 和PHP 的模塊版本之間性能比不同。無論您選擇哪種語言,最重要的是盡可能地避免獨立的解釋程序。
解釋程序的獨立版本的確有一個優點超過它的模塊版本,即可以安排它在不同的用戶ID下運行。模塊版本始終運行在與Web 服務器相同的用戶ID 下,出於安全原因,該用戶是一個典型的具有很少權限的賬號。對於需要特殊權限的腳本來說不能很好地運行(例如,如果您需要能讀寫受保護的文件)。如果願意,可以將模塊方法和獨立方法結合起來:缺省情況下使用模塊版本,而在具有特定用戶的權限的腳本的情況下使用獨立版本。
降低mod_perl 的內存需求
有些技術允許您只能對mod_perl 使用某些的Apache 進程。這樣,只對運行Perl 腳本的那些進程產生額外的內存開銷。apache Web 站點的mod_perl 部分有可選擇的各種策略的討論(有關的詳細信息,請參閱h t t p : / / per l . a p a c h e . o rg / g ui d e /)。綜上考慮,也就是說,選擇Perl 還是PHP,您應該試著從Apache 模塊中而不是通過調用一個單獨的解釋程序過程來使用它。只對不能由模塊處理的那些情況使用獨立的解釋程序,例如需要特殊權限的腳本。對於這些實例,可以通過使用apache 的suEXEC 機制在給定的用戶ID 下啟動解釋程序來處理腳本。
5.2.3 開發時間
剛才描述的這些因素影響應用程序的性能,但不能只考慮運行效率。時間及編程的簡易性也是重要的,所以為MySQL編程選擇API 時要考慮的另一個因素是如何很快地開發出自己的應用程序。如果開發同樣程序,用Perl腳本只需用C 語言一半的時間,那您可能寧願使用Perl DBI API,而非C API,即使開發出的應用程序運行速度不是非常快也如此。考慮程序的運行時間比考慮編寫程序時花的時間更少一些通常是合理的,特別是對不經常運行的應用程序更是如此。您的一小時比機器的一小時要值錢得多!
一般來說,腳本語言編寫程序更快,特別是得到應用程序的原型更快,這是由於以下兩個原因:
第一,腳本語言提供更高級別的結構。這允許您在抽象的更高級別上進行思考,以便集中考慮要做些什麼,而不是考慮如何做。例如, Perl 的關聯數組(散列)對於維護具有鍵/值系(如學生ID /學生姓名對)的數據節省了大量時間。C 沒有這樣的構造。如果想在C 中實現這樣的事情,則可能需要編寫代碼來處理許多低級的細節,其中包括內存管理和串操縱的問題,並且需要調試它,這也要花時間。
第二,腳本語言的開發周期的步驟較少。用C 開發應用程序時,要經歷通常的編輯—編譯—測試的循環周期。每次修改程序時,在測試之前都必須重新編譯它。而用Perl 和PHP,由於每次修改後不用編譯就可以立即運行腳本,因此,開發周期可簡化為編輯—測試。另一方面,編譯程序對程序在嚴格的類型檢查形式方面有更多的約束條件。編譯程序施加的更多約束條件有助於避免在松散語言(如Perl 和PHP )中不易捕獲的錯誤。在C 中,如果您錯誤地拼寫了變量的名稱,則編譯程序將警告您。PHP 不這樣,Perl 也不這樣,除非向它詢問。當應用程序變得更大且更難於維護時,這些更嚴格的約束條件可能特別有用。
一般來說,在編譯和解釋語言之間權衡的是開發時間與性能的折衷:是想要使用編譯語言開發程序,以便在運行時可以更快,但花費更多的時間來編寫它?還是想要用腳本語言編寫程序,以便在縮短編程時間,但要損失一些運行速度?
將兩種方法合並起來也是可能的。編寫一個腳本作為“第一個草案”來快速地開發出一個應用程序原型以測試其邏輯性,確定算法的可用性。如果這個程序有用,並且被頻繁使用,則性能成為關心的焦點,這時可作為編譯的應用程序重新對它編寫代碼。這樣做給您帶來兩種方法的優點:快速得到應用程序的初始開發原型,同時得到最終產品的最佳性能。從某種嚴格的意義來說, Perl DBI 和PHP API 並沒有給您在C 客戶機庫中沒有的能力。這是因為這兩種API 通過MySQLC 庫連接到Perl 和PHP 解釋程序來獲取對MySQL的訪問。然而,對於嵌入MySQL的環境,C 與Perl 或PHP 有很大的不同。應考慮在與MySQL服務器相互作用時要做的事情並提問每個API 語言如何幫助您完成這些事情。下面有一些樣例:
■ 內存管理。在C中,您發現自己對任何任務,包括動態分配數據結構都使用malloc() 和free() 來工作。Perl 和PHP 可為您處理這些任務。例如,數組的大小自動地增加,並且可以使用動態長度的字符串而不用考慮內存管理。
■ 文本處理。在這點Perl 具有最大的開發能力,而PHP 位於第二。比較起來,C 是非常初級的。當然,可以用C編寫自己的庫,將內存管理和文本處理這樣一些任務封裝成更容易工作的函數。但是,然後還必須調試它們,並且您也想使自己的算法效率更高。在這兩個方面,基本上可以斷定,由於它們已經具有了通過許多雙眼睛檢查過的好處,對這些事情Perl 和PHP中的算法一般是易於調試並且有合理的效率。通過利用其他人的工作可以節省您的時間(另一方面,如果解釋程序偶爾有一個錯誤,您可能必須攜帶它,直到這個問題糾正為止。而用C 編寫時,可以更細地控制程序性能)。
這些語言的不同還在於它們的“安全性”。C API 提供對服務器最低級別的接口,而且強制的原則最少。從這種意義上說,它提供最低級的安全性網絡。如果您超出正常順序執行API 函數,則可能獲得一個“超出同步”的錯誤,或使程序崩潰。Perl 和PHP 都提供了很好的保護。如果您沒有以適當的順序進行,則腳本失敗,但是解釋程序並不崩潰。在C 程序中,出現崩潰錯誤的另一個非常可能的來源是動態分配內存和與它們相關的指針的使用。Perl 和PHP 為您處理內存管理,所以您的腳本很少可能因為內存管理的錯誤而癱瘓。
開發時間受語言可用的外部支持的影響。C 可用的外部支持是將MySQLC API 函數封裝為更容易使用的實例的包裝庫的形式。這些庫對於C 和C++ 都可用。Perl 無疑具有最大數量的附加軟件,都是Perl 模塊的形式(與在apache 模塊中具有的概念類似)。甚至有一個基礎結構被設計來容易地定位並獲取這些模塊(即綜合Perl 歸檔網絡Comprehensive Perl Archive Network, CPA N)。使用Perl 模塊,不用編寫代碼就可以獲取對所有類型的函數的訪問。想要編寫從數據庫中生成報告的腳本,然後作為一個附件發送給某人嗎?只要獲取MIME 模塊中的一個,就立即具有附件生成的能力。
PHP 沒有同樣程度的外部支持(這並不令人驚奇,因為它是較新的語言)。也許所知道的最佳的附加軟件是PHP基本庫( PHP Base Library,PHP LIB)。根據名稱和口令機制的一些排序,假設您正在編寫需要限定只有經授權的用戶才可以對某個Web 頁面訪問的Web 應用程序。可以用任意語言編寫對它的支持程序,但是如果使用PHP L I B,則不必花費時間重新做這件事情。PHP L I B提供確認並且允許通過會話跟蹤經授權的用戶(從作為單個邏輯訪問部分的給定客戶機中連續頁面的命中)。還可以分配給用戶許可權,這允許您進行像定義具有更多權限的管理用戶的工作。
5.2.4 可移植性
可移植性的問題與為訪問MySQL引擎所編寫的程序怎樣才能容易地修改為使用不同引擎的程序有關。您可能不擔心這個事情。然而,除非可以預知未來,否則,說“除了MySQL以外,我永遠都不會將這個程序用在任何其他的數據庫上”可能有些冒險:假設您找到另一份工作,並想使用自己的舊程序,但您的新老板使用不同的數據庫系統呢?如果可移植性是需要優先考慮的事情,則應該考慮在API 之間的區別:
■ DBI API的可移植性最好,因為它獨立於數據庫是DBI 設計的一個明確目標。
■ PHP 的可移植性稍差,因為它不提供對DBI 提供的各種數據庫引擎的同樣類型的統一接口。對每個支持數據庫的PHP 函數的調用類似於在相應的基礎C API 中的那些。稍有一些不同,但很少,需要更改您調用的數據庫相關函數的名稱。還有可能要修改一點應用程序的邏輯,因為不同數據庫的借口並不都是以同樣的方式工作的。
■ C API 提供的數據庫之間的可移植性最差。因為它生來就是為MySQL設計的。當需要在同一個應用程序中訪問多個數據庫系統時,獨立於數據庫的可移植性特別重要。這可能包括像將數據從一個RDBMS 移動到另一個RDBMS 中的簡單任務,或更復雜的任務,如基於從許多數據庫系統中得到的信息生成報告。
DBI 和PHP 都提供對訪問多個數據庫引擎的支持,所以對不同的數據庫,甚至在不同的主機上,都可以很容易地同時連接到服務器上。然而, DBI 和PHP 在對於從多個異構數據庫系統中檢索和處理數據的任務的適宜性方面有所不同。而DBI 更好些,因為無論使用哪種數據庫,它都使用一組單獨的訪問調用。假設想在MySQL、mSQL 和Postgres 數據庫之間傳送數據。使用DBI,則使用這三種數據庫的惟一不同之處在於用於連接到每個服務器的DBI -> connect( )調用。而用PHP時,可能需要有更復雜的腳本,該腳本將含有三組讀取調用和三組寫入調用。
多數據庫應用程序的一個極好的例子是MySQL分發包中的crash-me 腳本,它可測試許多不同的數據庫服務器的能力。該腳本是用DBI編寫的,對於這樣的應用程序,這種選擇是很明顯的,因為您可以同樣的方式訪問所有的數據庫。