直播中
要想正確回答這個(gè)問(wèn)題,需要在兩個(gè)不同情況下檢驗(yàn)測(cè)試結(jié)果:第一是每頁(yè)執(zhí)行一個(gè)數(shù)據(jù)庫(kù)處理的情況,第二是每頁(yè)執(zhí)行多個(gè)數(shù)據(jù)庫(kù)處理的情況。
在前面的例子中,我們已經(jīng)創(chuàng)建了一個(gè)單獨(dú)的Connection對(duì)象,并將它傳遞到記錄集的ActiveConnection 屬性。但是也有可能僅僅把連接字符串傳遞到這個(gè)屬性中,從而可以避免一個(gè)額外的步驟,即在腳本( ADO__03.asp )中例示和配置一個(gè)單獨(dú)的組件:
objRS.ActiveConnection = Application("Conn")
盡管我們?nèi)匀辉谟涗浖袆?chuàng)建了一個(gè)連接,但它是在非常優(yōu)化的情況下創(chuàng)建的,所以剛一開(kāi)始我們就看到啟動(dòng)時(shí)間比以前的測(cè)試減少了23%,同預(yù)料中一樣,同每個(gè)記錄的顯示時(shí)間幾乎沒(méi)有什么差別。
因此,我們的第二個(gè)規(guī)則是:
* 當(dāng)使用一個(gè)單個(gè)記錄集時(shí),將連接字符串傳遞到ActiveConnection屬性中。
下面要確定當(dāng)在一個(gè)頁(yè)面上創(chuàng)建多個(gè)記錄集時(shí),這個(gè)邏輯是否依然成立。為測(cè)試這個(gè)情況,我引入了FOR 循環(huán),將前面的例子重復(fù)10次。在這個(gè)測(cè)試中,我們還將研究3種選擇:
第一,我們?cè)诿總€(gè)循環(huán)中創(chuàng)建并銷毀Connection 對(duì)象( ADO__04.asp ):
Dim i
For i = 1 to 10
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open Application("Conn")
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.ActiveConnection = objConn
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application("SQL")
If objRS.EOF Then
Response.Write("No Records Found")
Else
'write headings
...
'write data
...
End If
objRS.Close
Set objRS = Nothing
objConn.Close
Set objConn = Nothing
Next
第二,在循環(huán)外創(chuàng)建一個(gè)單獨(dú)的Connection 對(duì)象,并與每個(gè)記錄集共享它( ADO__05.asp ):
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open Application("Conn")
Dim i
For i = 1 to 10
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.ActiveConnection = objConn
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application("SQL")
If objRS.EOF Then
Response.Write("No Records Found")
Else
'write headings
...
'write data
...
End If
objRS.Close
Set objRS = Nothing
Next
objConn.Close
Set objConn = Nothing
第三,在每個(gè)循環(huán)中將連接字符串傳遞到ActiveConnection 屬性( ADO__06.asp ):
Dim i
For i = 1 to 10
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.ActiveConnection = Application("Conn")
objRS.CursorType = 0 'adOpenForwardOnly
objRS.LockType = 1 'adLockReadOnly
objRS.Open Application("SQL")
If objRS.EOF Then
Response.Write("No Records Found")
Else
'write headings
...
'write data
...
End If
objRS.Close
Set objRS = Nothing
Next
你可能已經(jīng)猜到了,在每個(gè)循環(huán)中創(chuàng)建并銷毀Connection 對(duì)象是一個(gè)低效率的方法。但是令人吃驚的是,僅僅在每個(gè)循環(huán)中傳遞連接字符串比共享單一連接對(duì)象的效率只低一點(diǎn)點(diǎn)。
盡管如此,我們的第3條規(guī)則是:
* 在一個(gè)頁(yè)面上使用多個(gè)記錄集時(shí),創(chuàng)建一個(gè)Connection 對(duì)象,在ActiveConnection 屬性中重復(fù)使用它。
指針和鎖的類型中,哪些是最有效的?
到目前為止,我們所有測(cè)試都只用了只向前(Forward Only )的指針在記錄集中循環(huán)。但是,ADO還為記錄集提供了3種類型的指針:Static, Dynamic 和 Keyset。每一種都提供了額外的功能,比如向前和向后移動(dòng)以及當(dāng)別人建立數(shù)據(jù)時(shí)可以看到修改情況的功能。不過(guò),討論這些指針類型的內(nèi)涵不是本文討論的范圍。我把這些留給你自己。下面是各種類型的比較分析。
與它們的同類Forward Only 相比,這些額外的指針都明顯地造成了更大的負(fù)載( ADO__03.asp )。另外這些指針在循環(huán)期間也更慢。我想與你一起分享的一條忠告是要避免這種想法:“我不時(shí)地需要一下Dynamic 指針,所以干脆總是用它算了?!?
從本質(zhì)上說(shuō),同樣的問(wèn)題也適用于鎖的類型。前面的測(cè)試中只使用了Read Only(只讀)類型的鎖。但是,還有三種類型的鎖:Lock Pessimistic、 Lock Optimistic和Lock Batch Optimistic。同指針的選擇一樣,這些鎖也為處理記錄集中的數(shù)據(jù)提供了額外的功能和控制。同樣,我將學(xué)習(xí)每種鎖設(shè)置的適當(dāng)用途的內(nèi)容留給你自己。
所以引導(dǎo)我們考慮規(guī)則4的邏輯很簡(jiǎn)單:使用最適合你的任務(wù)的最簡(jiǎn)單的指針和鎖的類型。
獲取一個(gè)記錄集最好的方式是什么?
到目前為止,我們只是通過(guò)Recordset 對(duì)象來(lái)恢復(fù)記錄集。但是ADO還提供了一些獲取記錄集的間接方法。下一個(gè)測(cè)試就將ADO__03.asp 中的值與直接從一個(gè)Connection對(duì)象中創(chuàng)建一個(gè)記錄集對(duì)象( CONN_01.asp )來(lái)比較。
Set objConn = Server.CreateObject("ADODB.Connection")
objConn.Open Application("Conn")
Set objRS = objConn.Execute(Application("SQL"))
我們看到,負(fù)載有一個(gè)輕微的增加,顯示每條記錄的時(shí)間沒(méi)有變化。
然后,我們看看從一個(gè)Command 對(duì)象中直接創(chuàng)建一個(gè)Recordset 對(duì)象( CMD__01.asp ):
Set objCmd = Server.CreateObject("ADODB.Command")
objCmd.ActiveConnection = Application("Conn")
objCmd.CommandText = Application("SQL")
Set objRS = objCmd.Execute
我們?cè)俅慰吹截?fù)載有一個(gè)輕微的增加,每個(gè)記錄的顯示時(shí)間有一個(gè)名義上的區(qū)別。雖然最后這兩種方法對(duì)性能的影響很小,卻有一個(gè)大問(wèn)題需要考慮。
通過(guò)Recordset 類創(chuàng)建一個(gè)記錄集對(duì)于控制如何處理記錄集提供了最大的靈活性。雖然其它方法也沒(méi)有提出一個(gè)壓倒性的性能問(wèn)題,但是你會(huì)被默認(rèn)狀態(tài)下返回何種指針類型和鎖類型而困惑,這些對(duì)于你的特定需求來(lái)說(shuō)不一定是最優(yōu)的。
所以,除非因?yàn)槟撤N特殊原因你需要其它方法的話,請(qǐng)遵循第5條規(guī)則:通過(guò)ADODB.Recordset 類例示記錄集以獲得最好的性能和最大的靈活性。
是否應(yīng)該斷開(kāi)記錄集?
ADO為斷開(kāi)一個(gè)記錄集提供了一種選擇,記錄集要在一個(gè)向前查詢中恢復(fù)所有數(shù)據(jù)、關(guān)閉連接、使用一個(gè)本地(或客戶)指針在數(shù)據(jù)集中移動(dòng)。這還提供了一個(gè)早期釋放連接的機(jī)會(huì)。這種情況對(duì)于處理遠(yuǎn)程數(shù)據(jù)服務(wù)是必要的,因?yàn)檫@種情況下數(shù)據(jù)必須從數(shù)據(jù)庫(kù)斷開(kāi)。但是對(duì)于普通的用途,這樣做有好處嗎?
下面我們?cè)黾恿薈ursorLocation 屬性,打開(kāi)記錄集后關(guān)閉連接( CLIENT1.asp ):
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.CursorLocation = 3 ' adUseClient
objRS.ActiveConnection = Application("Conn")
objRS.LockType = 1 ' adLockReadOnly
objRS.Open Application("SQL")
objRS.ActiveConnection = Nothing
從理論上說(shuō),這個(gè)技術(shù)應(yīng)該導(dǎo)致性能更快。原因有兩個(gè):首先,在記錄集中移動(dòng)時(shí),避免了通過(guò)連接的重復(fù)請(qǐng)求;其次通過(guò)較早地取消連接減輕了資源需求。但是,在使用客戶端指針時(shí),效率低得很明顯。可能是由于當(dāng)使用客戶指針位置時(shí),不管你的設(shè)置是什么,CursorType 都被修改成Static。
規(guī)則6是這樣的:除非是一個(gè)斷開(kāi)的環(huán)境中所要求的,避免使用斷開(kāi)的記錄集。
什么是設(shè)置記錄集屬性的最好方法?
前面所有的測(cè)試都是通過(guò)單獨(dú)的屬性設(shè)置來(lái)直接設(shè)置記錄集的屬性的。但是Recordset.Open 函數(shù)可以為我們所需要的全部屬性接收額外的參數(shù)。雖然對(duì)于每個(gè)屬性來(lái)說(shuō),單獨(dú)的代碼行易于閱讀和維護(hù),它們還是要分別執(zhí)行一個(gè)單獨(dú)函數(shù)調(diào)用,必須通過(guò)COM界面來(lái)集合( ADO__07.asp ):
Set objRS = Server.CreateObject("ADODB.Recordset")
objRS.Open Application("SQL"), Application("Conn"), 0, 1
' adForwardOnly, adLockReadOnly
這些方法在負(fù)載上帶來(lái)得差別小得驚人,于是我們得到規(guī)則7:不要對(duì)單獨(dú)設(shè)置記錄集屬性感到擔(dān)心。