免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
提升數(shù)據(jù)訪問層的性能(二)
提升數(shù)據(jù)訪問層的性能(二) 收藏
3.    選擇優(yōu)化性能的功能

3.1.    使用參數(shù)標(biāo)記作為存儲過程的參數(shù)
    調(diào)用存儲過程時,用參數(shù)標(biāo)記做為參數(shù)盡量不要用字符做參數(shù)。JDBC驅(qū)動調(diào)用存儲過程時要么象執(zhí)行其他SQL查詢一樣執(zhí)行該過程,要么通過RPC直接調(diào)用來優(yōu)化執(zhí)行過程。如果象SQL查詢那樣執(zhí)行存儲過程,數(shù)據(jù)庫服務(wù)器先解析該語句,驗(yàn)證參數(shù)類型,然后把參數(shù)轉(zhuǎn)換成正確的數(shù)據(jù)類型,顯然這種調(diào)用方式不是最高效的。
    SQL語句總是做為一個字符串送到數(shù)據(jù)庫服務(wù)器上,例如,
“{call getCustName (12345)}”。
在這種情況下,即使程序員設(shè)想給getCustName唯一的參數(shù)是整型,事實(shí)上參數(shù)傳進(jìn)數(shù)據(jù)庫的仍舊是字符串。數(shù)據(jù)庫服務(wù)器解析該語句,分離出單個參數(shù)值12345,然后在把過程當(dāng)作SQL語言執(zhí)行之前,將字符串“12345”轉(zhuǎn)換成整型值。
    通過RPC在數(shù)據(jù)庫服務(wù)器中調(diào)用存儲過程,就能避免使用SQL字符串帶來的開銷。
    情形1
    在這個例子中,就不能使用服務(wù)器端的RPC優(yōu)化調(diào)用存儲過程。調(diào)用的過程包括解析語句,驗(yàn)證參數(shù)類型,在執(zhí)行過程之前把這些參數(shù)轉(zhuǎn)換成正確的類型。
CallableStatement cstmt = conn.prepareCall (   "{call getCustName (12345)}"); ResultSet rs = cstmt.executeQuery (); 
    情形2
    在這個例子中,可以使用服務(wù)器端RPC優(yōu)化調(diào)用存儲過程。由于應(yīng)用避免了文字參數(shù)傳遞帶來的開銷,且JDBC能以RPC方式直接在數(shù)據(jù)庫中調(diào)用存儲過程來優(yōu)化執(zhí)行,所以,執(zhí)行時間也大大地縮短了。
CallableStatement cstmt =
     conn.prepareCall (   "{call getCustName (?)}");cstmt.setLong (1,12345);
ResultSet rs = cstmt.executeQuery();
    JDBC根據(jù)不同的用途來優(yōu)化性能,所以我們需要根據(jù)用途在PreparedStatement對象和Statement對象之間做出選擇。如果執(zhí)行一個單獨(dú)的SQL語句,就選擇Statement對象;如果是執(zhí)行兩次或兩次以上就選擇PreparedStatement對象。
    有時,為了提高性能我們可以使用語句池。當(dāng)使用語句池時,如果查詢被執(zhí)行一次且可能再也不會被執(zhí)行,那就使用Statement對象。如果查詢很少被執(zhí)行,但在語句池的生命期內(nèi)可能再一次被執(zhí)行,那么使用PreparedSatement。在相同的情形下,如果沒有語句池,就使用Statement對象。
3.2.    用批處理而不是用PreparedStatement語句
    更新大量的數(shù)據(jù)通常是準(zhǔn)備一個INSERT語句并多次執(zhí)行該語句,結(jié)果產(chǎn)生大量的網(wǎng)絡(luò)往返。為了減少JDBC調(diào)用次數(shù)和提高性能,你可以使用PreparedStatement對象的addBatch()方法一次將多個查詢送到數(shù)據(jù)庫里。例如,讓我們比較一下下邊的例子,情形1和情形2。
    情形1:多次執(zhí)行PreparedStatement語句
PreparedStatement ps = conn.prepareStatement("INSERT into employees values (?, ?, ?)");
for (n = 0; n < 100; n++) { 
 ps.setString(name[n]);
 ps.setLong(id[n]); 
 ps.setInt(salary[n]);
 ps.executeUpdate();
}
    情形2:使用批處理
PreparedStatement ps =
conn.prepareStatement(   "INSERT into employees values (?, ?, ?)");
for (n = 0; n < 100; n++) { 
ps.setString(name[n]); 
ps.setLong(id[n]); 
ps.setInt(salary[n]); 
ps.addBatch();
}
ps.executeBatch();
    在情形1中,一個PreparedStatement用于多次執(zhí)行一個INSERT語句。在這個情況下,為了100次插入需要101次網(wǎng)絡(luò)往返,其中一次用于準(zhǔn)備語句,額外100次網(wǎng)絡(luò)往返用于執(zhí)行每一個操作。當(dāng)addBatch()方法的時候,如情形2所述,僅需要兩個網(wǎng)絡(luò)往返,一個準(zhǔn)備語句,另一個執(zhí)行批處理。盡管使用批處理需要更多的數(shù)據(jù)庫CPU運(yùn)算開銷,但性能可由減少的網(wǎng)絡(luò)往返獲得。記住要讓JDBC驅(qū)動在性能方面有良好的表現(xiàn),就要減少JDBC驅(qū)動和數(shù)據(jù)庫服務(wù)器之間的網(wǎng)絡(luò)通訊量。
3.3.    選擇合適的游標(biāo)
    選擇合適的游標(biāo)能提高應(yīng)用的靈活性。本節(jié)總結(jié)了三類游標(biāo)的性能問題。向前游標(biāo)對連續(xù)讀表中所有的行提供了優(yōu)秀的性能。就檢索表數(shù)據(jù)而言,沒有一個檢索數(shù)據(jù)的方法要比向前游標(biāo)更快。然而,當(dāng)應(yīng)用必須處理非連續(xù)方式的行時,就不能使用它。
    對需要數(shù)據(jù)庫高層次的并發(fā)控制和需要結(jié)果集向前和向后滾動能力的應(yīng)用而言,JDBC驅(qū)動使用的無感知游標(biāo)是最為理想選擇。對無感知游標(biāo)的第一次請求是獲取所有的行(或者當(dāng)JDBC使用“懶惰”方式讀時,可以讀取部分行)并將它們存儲在客戶端。那么,第一次請求將會非常慢,特別是當(dāng)長數(shù)據(jù)被檢索到的時候。后續(xù)的請求不再需要網(wǎng)絡(luò)交通(或當(dāng)驅(qū)動采用懶惰方式時,只有有限的網(wǎng)絡(luò)交通)并處理得很快。由于第一次請求處理緩慢,無感知游標(biāo)不應(yīng)該用于一行數(shù)據(jù)的單個請求。當(dāng)要返回長數(shù)據(jù)時,內(nèi)存很容易被耗盡,所以開發(fā)人員也應(yīng)該避免使用無感知游標(biāo)。一些無感知游標(biāo)的實(shí)現(xiàn)是把數(shù)據(jù)緩存在數(shù)據(jù)庫中的零時表中,避免了性能問題,但是,大多數(shù)是把信息緩存在應(yīng)用本地。
    無感知游標(biāo),有時又叫鍵集驅(qū)動的游標(biāo),使用標(biāo)識符,如已經(jīng)存在于你數(shù)據(jù)庫中的ROWID。當(dāng)你通過結(jié)果集滾動的時候,適合于標(biāo)識符的數(shù)據(jù)會被檢索到。由于每個請求都產(chǎn)生網(wǎng)絡(luò)交通量,所以性能將會非常差。然而,返回非連續(xù)行不會更多的影響性能。
    為了更進(jìn)一步說明,我們來看一個通常返回應(yīng)用1000行數(shù)據(jù)的應(yīng)用。在執(zhí)行時或第一行被請求時,JDBC不會執(zhí)行由應(yīng)用提供的SELECT語句。而是JDBC驅(qū)動用鍵標(biāo)識符替換查詢的SELECT列表,例如,ROWID。這個修改的查詢將會被驅(qū)動執(zhí)行,并且所有1000鍵值將會被從數(shù)據(jù)庫中檢索出來并被驅(qū)動緩存。每一個來自應(yīng)用對結(jié)果行的請求將轉(zhuǎn)到JDBC驅(qū)動,為了返回合適的行,JDBC在它本地緩存中查詢鍵值,構(gòu)造一個類似于“WHERE ROWID=?”包含WHERE的優(yōu)化的語句,執(zhí)行這個修改了查詢,然后從服務(wù)器上檢索單個結(jié)果行。
    當(dāng)應(yīng)用使用來自緩存中的無感知(Insensitive)游標(biāo)數(shù)據(jù)時,有感知(Sensitive)游標(biāo)在動態(tài)情形下就是首選的游標(biāo)模式。
3.4.    有效地使用get方法
    JDBC提供了很多從結(jié)果集中檢索數(shù)據(jù)的方法,例如getInt(),getString(),以及getObject()。getObject()方法是最普通的方法,但在沒有說明非默認(rèn)映射時提供了最差的性能。這是因?yàn)闉榱舜_定被檢索值的類型和產(chǎn)生合適的映射,JDBC驅(qū)動必須做額外的處理。所以,總是使用能明確數(shù)據(jù)類型的方法。
    為了更好地提高性能,請?zhí)峁┍粰z索列的列數(shù)字,例如,getString(1),getLong(2),和getInt(3),而不是列名。如果列數(shù)字沒有說明,網(wǎng)絡(luò)流量是不受影響的,但轉(zhuǎn)換和查找的成本上升了。例如,假設(shè)你使用getString(“foo”)…驅(qū)動可能不得不將列的標(biāo)識符foo轉(zhuǎn)換成大寫(如果必要),并在列列表中用“foo”和所有的列名比較。如果提供了列數(shù)字,很大部分的處理都被節(jié)省了。
    例如,假如你有一個15列100行的結(jié)果集,列名沒有包括在結(jié)果集中。你感興趣的有三列,EMPLOEEMENT(字符串),EMPLOYEENUMBER(長整型),和SALARY(整型)。如果你說明了getString(“EmployeeName”),getLong(“EmployeeNumber”)和getInt(“Salary”),每列的列名必須轉(zhuǎn)換成和數(shù)據(jù)庫元數(shù)據(jù)中匹配的大小寫,毫無疑問查詢將相應(yīng)的增加。如果你說明getString(1),getLong(2),和getInt(15),性能將會大大地提高。
3.5.    檢索自動產(chǎn)生的鍵
    許多數(shù)據(jù)庫已經(jīng)隱藏了描述表中每行唯一鍵的列(又叫偽列)。通常,由于偽列描述了數(shù)據(jù)的物理磁盤地址,故而在查詢中使用這種類型的列存取行是最快的方式。在JDBC3.0以前,應(yīng)用僅能在插入數(shù)據(jù)之后立即執(zhí)行SELECT語句檢索到偽列的值。
For example:
//insert rowint
rowcount = stmt.executeUpdate (   "insert into LocalGeniusList (name) values ('Karen')");
// now get the disk address - rowid - for the newly inserted row
ResultSet rs = stmt.executeQuery (   "select rowid from LocalGeniusList where name = 'Karen'");
    這個檢索偽列的方法有兩個主要的缺點(diǎn)。第一,檢索偽列需要通過網(wǎng)絡(luò)把一個單獨(dú)的查詢語句發(fā)送到服務(wù)器上執(zhí)行。第二,由于表中可能沒有主鍵,查詢條件可能不能唯一地確定行。在后邊的情形中,多個偽列值被返回,應(yīng)用或許不能確定哪個是最近插入的行。
JDBC規(guī)范一個可選的特性是當(dāng)行插入表時,能檢索到行的自動產(chǎn)生的鍵信息。
For example:
int rowcount = stmt.executeUpdate (   "insert into LocalGeniusList (name) values ('Karen')",
// insert row AND return
keyStatement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys ();
// key is automatically available
    即便該表沒主鍵,這都給應(yīng)用提供了一個唯一確定行值的最快方法。當(dāng)存取數(shù)據(jù)時,檢索偽列鍵的能力給JDBC開發(fā)人員提供了靈活性并創(chuàng)造了性能。
4.    管理連接和數(shù)據(jù)更新

4.1.    管理連接
    連接管理的好壞直接影響到應(yīng)用的性能。采用一次連接創(chuàng)建多個Statement對象的方式來優(yōu)化你的應(yīng)用,而不是執(zhí)行多次連接。在建立最初的連接之后要避免連接數(shù)據(jù)源。
    一個不好的編碼習(xí)慣是執(zhí)行SQL語時連接和斷開好幾次。一個連接對象可以有多個Statement對象和它關(guān)聯(lián)。由于Statement對象是定義SQL語句信息的內(nèi)存存儲,它能管理多個SQL語句。此外,你可以使用連接池來顯著地提高性能,特別是對那些通過網(wǎng)絡(luò)連接或通過WWW連接的應(yīng)用。連接池讓你重用連接,關(guān)閉連接不是關(guān)閉與數(shù)據(jù)庫的物理連接,而是將用完的連接放到連接池中。當(dāng)一個應(yīng)用請求一個連接時,一個活動的連接將從連接池中取出重用,這樣就避免了創(chuàng)建新連接的而產(chǎn)生的網(wǎng)絡(luò)I/O。
4.2.    在事務(wù)中管理提交
    由于磁盤I/O和潛在的網(wǎng)絡(luò)I/O,提交事務(wù)往往要慢。經(jīng)常使用WSConnection.setAutoCommit(false)來關(guān)閉自動提交設(shè)置。
    提交實(shí)際上包括了什么呢?數(shù)據(jù)庫服務(wù)器必須刷新包含更新的和新數(shù)據(jù)的磁盤上的每一個數(shù)據(jù)頁。這通常是一個對日志文件連續(xù)寫的過程,但也是磁盤I/O。默認(rèn)情況下,當(dāng)連接到數(shù)據(jù)源時,自動提交是打開的,由于提交每個操作需要大量的磁盤I/O,自動提交模式通常削弱了性能。此外,大部分?jǐn)?shù)據(jù)庫沒有提供本地的自動提交模式。對這種類型的服務(wù)器,JDBC驅(qū)動對每一個操作必須明確地給服務(wù)器送出COMMIT語句和一個BEGIN TRANSACTION。
    盡管使用事務(wù)對應(yīng)用的性能有幫助,但不要過度地使用。由于為了防止其他用戶存取該行而在行上長時間的持有鎖將減少吞吐量。短時間內(nèi)提交事務(wù)可以最大化并發(fā)量。
4.3.    選擇正確的事務(wù)模式
    許多系統(tǒng)支持分布式事務(wù);也就是說,事務(wù)能跨越多個連接。由于記錄日志和所有包含在分布式事務(wù)中組件(JDBC驅(qū)動,事務(wù)監(jiān)視器和數(shù)據(jù)庫系統(tǒng))之間的網(wǎng)絡(luò)I/O,分布式事務(wù)要比普通的事務(wù)慢四倍。除非需要分布式事務(wù),否則盡量避免使用它們。如果可能就使用本地事務(wù)。應(yīng)該注意的是許多Java應(yīng)用服務(wù)器提供了一個默認(rèn)的利用分布式事務(wù)的事務(wù)行為。為了最好的系統(tǒng)性能,把應(yīng)用設(shè)計(jì)在運(yùn)行在單個連接對象之下,除非必要避免分布式事務(wù)。
4.4.    使用updateXXX方法
    盡管編程的更新不適用于所有類型的應(yīng)用,但開發(fā)人員應(yīng)該試著使用編程的更新和刪除,也就是說,使用ResultSet對象的updateXXX()方法更新數(shù)據(jù)。這個方法能讓開發(fā)人員不需要構(gòu)建復(fù)雜的SQL語句就能更新數(shù)據(jù)。為了更新數(shù)據(jù)庫,在結(jié)果集中的行上移動游標(biāo)之前,必須調(diào)用updateRow()方法。
    在下邊的代碼片斷中,結(jié)果集對象rs的Age列的值使用getInt()方法檢索出來,updateInt()方法用于用整型值25更新那一列。UpdateRow()方法用于在數(shù)據(jù)庫中更新修改了值的行。
int n = rs.getInt("Age");
// n contains value of Age column in the resultset rs...
rs.updateInt("Age", 25);
rs.updateRow();
    除了使應(yīng)用更容易地維護(hù),編程更新通常產(chǎn)生較好的性能。由于指針已經(jīng)定位在被更新的行上,定位行的所帶來的開銷就避免了。
4.5.    使用getBestRowIdentifier()
    使用getBestRowIdentifier()(請參閱DatabaseMetaData接口說明)確定用在更新語句的Where子句中的最優(yōu)的列集合。偽列常常提供了對數(shù)據(jù)的最快的存取,而這些列僅能通過使用getBestRowIdentifier()方法來確定。
    一些應(yīng)用不能被設(shè)計(jì)成利用位置的更新和刪除。一些應(yīng)用或許通過使用可查詢的結(jié)果列,如調(diào)用getPrimaryKeys()或者調(diào)用getIndexInfo()找出可能是唯一索引部分的列,使Where子句簡潔化。這些方法通??梢怨ぷ?,但可能產(chǎn)生相當(dāng)復(fù)雜的查詢??纯聪逻叺睦樱?br>ResultSet WSrs = WSs.executeQuery    ("SELECT first_name, last_name, ssn, address, city, state, zip    FROM emp");
// fetch data...
WSs.executeUpdate ("UPDATE EMP SET ADDRESS = ?   WHERE first_name = ? and last_name = ? and ssn = ?    and address = ? and city = ? and state = ?    and zip = ?");
// fairly complex query
    應(yīng)用應(yīng)該調(diào)用getBestRowIdentifier()檢索最優(yōu)集合的能確定明確的記錄的列(可能是偽列)。許多數(shù)據(jù)庫支持特殊的列,它們沒有在表中被用戶明確地定義,但在每一個表中是“隱藏”的列(例如,ROWID和TID)。由于它們是指向確切記錄位置的指針,這些偽列通常給數(shù)據(jù)提供了最快的存取。由于偽列不是表定義的部分,它們不會從getColumns中返回。為了確定偽列是否存在,調(diào)用getBestRowIndentifier()方法。
再看一下前邊的例子:
...
ResultSet WSrowid = getBestRowIdentifier(... "emp", ...);
...
WSs.executeUpdate ("UPDATE EMP SET ADDRESS = ?  WHERE ROWID = ?";
// fastest access to the data!
    如果你的數(shù)據(jù)源沒有包含特殊的偽列,那么getBestRowIdentifier()的結(jié)果集由指定表上的唯一索引組成(如果唯一索引存在)。因此,你不需要調(diào)用getIndexInfo來找出最小的唯一索引。

本文來自CSDN博客,轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/chensheng913/archive/2004/08/29/88297.aspx
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
JDBC常見面試題集錦
JDBC應(yīng)用程序常見接口API和基本操作步驟
Java中JDBC常見對象
JDBC介紹
Java的數(shù)據(jù)庫連接編程(JDBC)技術(shù)
jdbc編程中的一些常用的技巧[總結(jié)]
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服