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

打開APP
userphoto
未登錄

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

開通VIP
Oracle occi 批量插入數(shù)據(jù)

在用OCCI 向Oracle中插入數(shù)據(jù)時(shí),效率不高,使用自動(dòng)提交數(shù)據(jù)的情況(默認(rèn))下一秒鐘只能插入1000條數(shù)據(jù)左右。因?yàn)椴迦霐?shù)據(jù)庫這塊是影響系統(tǒng)中效率最明顯的地方,因此很有必要提高數(shù)據(jù)插入這塊的效率。在網(wǎng)上找了一些資料后發(fā)現(xiàn),可以重用statement對象,使用批量插入的方法,先把數(shù)據(jù)保存在內(nèi)存中,積累到一定數(shù)值之后批量插入Oracle,這樣平均下來一秒鐘可以插入5000多條數(shù)據(jù),性能有所提高,不錯(cuò),這里做一個(gè)記錄。

  1. #include <iostream>  
  2. #include <string.h>  
  3. #include <time.h>  
  4. #include <sys/time.h>   
  5.   
  6. #define WIN32COMMON //避免函數(shù)重定義錯(cuò)誤  
  7. #include <occi.h>  
  8. #include <cstdlib>  
  9. #include <map>  
  10. #define ArraySize 10000  //內(nèi)存中數(shù)據(jù)滿1000條批量插入到oracle中  
  11.   
  12. using namespace oracle::occi;  
  13. using namespace std;  
  14.   
  15. /* 
  16.  *返回當(dāng)前時(shí)間,用于計(jì)算兩個(gè)操作的時(shí)間差 
  17.  */  
  18. long getCurrentTime()  
  19. {  
  20.    struct timeval tv;  
  21.    gettimeofday(&tv,NULL);  
  22.    return tv.tv_sec * 1000 + tv.tv_usec / 1000;  
  23. }  
  24.   
  25. /* 
  26.  * @author: roger 
  27.  */  
  28. int main(void)  
  29. {  
  30.   
  31.     string username = "XX";  
  32.     string pass = "XXX";  
  33.     string srvName = "XXX";  
  34.     Environment *env ;  
  35.     Connection *conn;  
  36.     Statement *stmt;  
  37.     try  
  38.     {  
  39.         env = Environment::createEnvironment(Environment::THREADED_MUTEXED);  
  40.         conn = env->createConnection(username, pass, srvName);  
  41.   
  42.         string sql = "insert into instant_infor (motor_id, lat, lon, uploadTime, receivetime, state_id, sys_state_id) values(:fld1,:fld2,:fld3,to_timestamp(:fld4,'yyyy-mm-dd hh24:mi:ss'),to_timestamp(:fld5,'yyyy-mm-dd hh24:mi:ss'),:fld6,:fld7)";  
  43.      stmt = conn->createStatement(sql);  
  44.   
  45.     } catch(SQLException e)  
  46.     {  
  47.         env = NULL;  
  48.         conn = NULL;  
  49.         cout<<e.what()<<endl;  
  50.     }  
  51.   
  52.       char motorid[ArraySize][12];  
  53.       char lat[ArraySize][20];  
  54.       char lon[ArraySize][20];  
  55.       char uploadTime[ArraySize][20];  
  56.       char createTime[ArraySize][20];  
  57.       char state_id[ArraySize][50];  
  58.       char sys_state_id[ArraySize][50];  
  59.   
  60.     ub2  motor_idLen[ArraySize] ;  
  61.     ub2  uploadTimeLen[ArraySize] ;  
  62.     ub2  createTimeLen[ArraySize];  
  63.     ub2  state_idLen[ArraySize];  
  64.     ub2  sys_state_idLen[ArraySize];  
  65.     ub2  latLen[ArraySize] ;  
  66.     ub2  lonLen[ArraySize] ;  
  67.   
  68.     long a1 = getCurrentTime();  
  69.     for(int i=0;i<ArraySize;i++){  
  70.   
  71.       strcpy(motorid[i],"10000100000");  
  72.       strcpy(lat[i] , "30.123");  
  73.       strcpy(lon[i] , "120.123");  
  74.       strcpy(uploadTime[i] , "2015-11-11 11:11:11");  
  75.       strcpy(createTime[i] , "2015-11-11 11:11:11");  
  76.       strcpy(state_id[i] ,"1");  
  77.       strcpy(sys_state_id[i],"1");  
  78.   
  79.       motor_idLen[i] = strlen( motorid[i] ) + 1;  
  80.       uploadTimeLen[i] = strlen( uploadTime[i] ) + 1;  
  81.       createTimeLen[i] = strlen( createTime[i] ) + 1;  
  82.       state_idLen[i] = strlen( state_id[i] ) + 1;  
  83.       sys_state_idLen[i] = strlen( sys_state_id[i] ) + 1;  
  84.       latLen[i] = strlen( lat[i] ) + 1;  
  85.       lonLen[i] = strlen( lon[i] ) + 1;  
  86.     }  
  87.   
  88.     stmt->setDataBuffer(1, (dvoid*)motorid, OCCI_SQLT_STR,sizeof( motorid[0] ), motor_idLen);  
  89.     stmt->setDataBuffer(2, (dvoid*)lat, OCCI_SQLT_STR, sizeof( lat[0] ), latLen);  
  90.     stmt->setDataBuffer(3, (dvoid*)lon, OCCI_SQLT_STR, sizeof( lon[0] ), lonLen);  
  91.     stmt->setDataBuffer(4, (dvoid*)uploadTime, OCCI_SQLT_STR, sizeof( uploadTime[0] ), uploadTimeLen);  
  92.     stmt->setDataBuffer(5, (dvoid*)createTime, OCCI_SQLT_STR, sizeof( createTime[0] ), createTimeLen);  
  93.     stmt->setDataBuffer(6, (dvoid*)state_id, OCCI_SQLT_STR,sizeof( state_id[0] ), state_idLen);  
  94.     stmt->setDataBuffer(7, (dvoid*)sys_state_id, OCCI_SQLT_STR, sizeof( sys_state_id[0] ), sys_state_idLen);  
  95.   
  96.     stmt->executeArrayUpdate(ArraySize);  
  97.     conn->terminateStatement(stmt);  
  98.     conn->commit();  
  99.   
  100.     long a2= getCurrentTime();  
  101.   
  102.     cout<<"插入"<<ArraySize<<"條數(shù)據(jù)完成"<<endl;  
  103.     cout<<"花費(fèi)時(shí)間: "<<(a2-a1)<<endl;  
  104.   
  105. }  

測試中是訪問本地的Oracle數(shù)據(jù)庫,用到的Makefile文件如下:

  1. CC=g++  
  2. OBJS=TestOracle.o  
  3. LIB=-L/opt/oracle/oracle11g/product/11.2.0/dbhome_1/lib -L/opt/oracle/oracle11g/product/11.2.0/dbhome_1/rdbms/lib/   
  4. INCLUDE=-I/opt/oracle/oracle11g/product/11.2.0/dbhome_1/precomp/public -I/opt/oracle/oracle11g/product/11.2.0/dbhome_1/rdbms/public  
  5. Test: $(OBJS)  
  6.     $(CC) -o Test $(OBJS) $(LIB) -locci -lclntsh   
  7. TestOracle.o: TestOracle.cpp    
  8.     $(CC) -c  TestOracle.cpp $(INCLUDE)  
  9. clean:  
  10.     rm -rf *.o  & rm Test  

程序的編寫是參考網(wǎng)上的一篇文章,寫的很好,這里作為參考:http://rgyq.blog.163.com/blog/static/3161253820131695957501/

  • 重用statement對象

每次創(chuàng)建statement對象時(shí),需要在客戶端和服務(wù)端分配資源,如內(nèi)存和游標(biāo)(cursor),用于存儲(chǔ)對象及數(shù)據(jù)。為了不必要的內(nèi)存重分配,應(yīng)重用statement對象。statement對象創(chuàng)建后,可以使用setSQL方法進(jìn)行重用,例如:

  1. Connection* conn = env->createConnection();   
  2. Statement* stmt = conn->createStatement();   
  3. stmt->setSQL(“INSERT INTO fruit_basket_tab VALUES(‘Apples’, 3)”);   
  4. stmt->executeUpdate();   
  5. stmt->setSQL(“INSERT INTO fruit_basket_tab VALUES(‘Oranges’, 4)”);   
  6. stmt->executeUpdate();   
  7. stmt->setSQL(“INSERT INTO fruit_basket_tab VALUES(‘Bananas’, 1)”);   
  8. stmt->executeUpdate();'   
  9. stmt->setSQL(“SELECT * FROM fruit_basket_tab WHERE quantity > 2”);   
  10. ResultSet* rs = stmt->executeQuery();  

  • statement參數(shù)化
為了進(jìn)一步控制內(nèi)存重新分配,可以通過參數(shù)化將前面3條SQL語句變成1條,然后設(shè)置參數(shù),再執(zhí)行。注意輸入?yún)?shù)的類型變化,因?yàn)?,每次改變參?shù)類型都會(huì)觸發(fā)重綁定。參數(shù)化示例如下:

  1. stmt->setSQL(“INSERT INTO fruit_basket_tab VALUES(:1, :2)”);   
  2. stmt->setString( 1, “Apples” );   
  3. stmt->setInt( 2, 3 );   
  4. stmt->executeUpdate();   
  5. stmt->setString( 1, “Oranges” );   
  6. stmt->setInt( 2, 4 );   
  7. stmt->executeUpdate();   
  8. stmt->setString( 1, “Bananas” );   
  9. stmt->setInt( 2, 1 );   
  10. stmt->executeUpdate();  
  • 批量更新
對于那些經(jīng)常發(fā)生的操作,很多時(shí)間都浪費(fèi)在與服務(wù)器網(wǎng)絡(luò)通信中。OCCI提供了有效的機(jī)制用于在單次網(wǎng)絡(luò)通信中發(fā)送多行信息。該優(yōu)化可用于INSERTs,UPDATEs和DELETEs。首先,設(shè)置最大迭代次數(shù),然后設(shè)置可變長度參數(shù)的最大長度。在迭代過程中參數(shù)類型不可變。具體細(xì)節(jié)參考OCCI Programmers Guide,第二章。下例是上面的INSERTs的優(yōu)化:

  1. //prepare the batching process   
  2. stmt->setMaxIterations( 3 );   
  3. stmt->setMaxParamSize( 1, 8 ); //”Bananas” is longest param   
  4. //batch the statements   
  5. stmt->setSQL(“INSERT INTO fruit_basket_tab VALUES(:1, :2)”);   
  6. stmt->setString( 1, “Apples” );   
  7. stmt->setInt( 2, 3 );   
  8. stmt->addIteration();   
  9. stmt->setString( 1, “Oranges” );   
  10. stmt->setInt( 2, 4 );   
  11. stmt->addIteration();   
  12. stmt->setString( 1, “Bananas” );   
  13. stmt->setInt( 2, 1 );   
  14. //execute the statements   
  15. stmt->executeUpdate();  
  • Statement::setDataBuffer方法
綁定值到參數(shù)化statements的參數(shù)時(shí)需要內(nèi)存拷貝,因?yàn)闉榱吮苊庑畔⒃谥虚g執(zhí)行過程中被覆蓋,所以必須拷貝到內(nèi)部的緩沖區(qū)中??截惖拇鷥r(jià)對于大字符串尤其明顯,內(nèi)存的消耗以及拷貝所花的時(shí)間。如果應(yīng)用可以自己管理內(nèi)存,就可以通過OCCI提供的方法最小化上述開銷。

雖然許多OCI開發(fā)者使用OCCI簡明的創(chuàng)建environments和statement對象,但仍然使用許多OCI中的類型。setDataBuffer方法允許OCI開發(fā)者執(zhí)行數(shù)組更新,最小化網(wǎng)絡(luò)通信次數(shù)。setDataBuffer方法與setXXX方法工作方法不同。一般說來,setXXX方法會(huì)將傳過來的數(shù)據(jù)拷貝到內(nèi)部緩沖區(qū)中,只要setXXX返回后參數(shù)值就可以被改變。然而,使用setDataBuffer方法可以避免將數(shù)據(jù)拷貝到內(nèi)部緩沖區(qū)中。代價(jià)是應(yīng)用程序在執(zhí)行完statement之前不可以修改緩沖區(qū)。例如:

  1. // insert Bananas   
  2. char buf[BUF_SIZE] = "Bananas";   
  3. int quantity = 1;   
  4. ub2 buflen = strlen( buf ) + 1;   
  5. ub2 quantlen = sizeof(int);   
  6. stmt->setDataBuffer(1, (dvoid*)buf, OCCI_SQLT_STR, buflen, &buflen);   
  7. stmt->setDataBuffer(2, (dvoid*)&quantity, OCCIINT, quantlen,   
  8. &quantlen);   
  9. stmt->executeUpdate(); // executeArrayUpdate(1) also would work.   
  10. // insert Apples   
  11. strcpy( buf, “Apples” );   
  12. quantity = 3;   
  13. buflen = strlen( buf ) + 1;   
  14. quantlen = sizeof( int );   
  15. stmt->setDataBuffer(1, (dvoid*)buf, OCCI_SQLT_STR, buflen, &buflen);   
  16. stmt->setDataBuffer(2, (dvoid*)&quantity, OCCIINT, quantlen,   
  17. &quantlen);   
  18. stmt->executeUpdate(); // executeArrayUpdate(1) also would work.   
  19. //commit the transaction   
  20. conn->commit();  
setDataBuffer方法可以與迭代執(zhí)行(iterative executes)和executeArrayUpdate方法結(jié)合使用。
  • executeArrayUpdate方法

當(dāng)進(jìn)行大量INSERTs和UPDATEs操作時(shí),可以通過executeArrayUpdate方法和setDataBuffer方法批量處理。這可以節(jié)省網(wǎng)絡(luò)通信,提高吞吐量。示例如下:

  1. char fruit[][BUF_SIZE] = { "Apples","Oranges","Bananas","Grapes" };   
  2. int int_arr[]={ 3,4,1,5 };   
  3. ub2 fruitlen[4]; // array of size of individual elements   
  4. ub2 intsize[4];   
  5. for(int i=0 ; i<4 ; i++)   
  6. {   
  7. intsize[i] = sizeof(int);   
  8. fruitlen[i] = strlen( fruit[i] ) + 1 ; // include the null   
  9. }   
  10. stmt->setDataBuffer(1, (dvoid*)fruit, OCCI_SQLT_STR, BUF_SIZE,   
  11. fruitlen);   
  12. stmt->setDataBuffer(2, (dvoid*)int_arr, OCCIINT, sizeof(int), intsize);   
  13. stmt->executeArrayUpdate(4);   
  14. conn->commit();  

executeArrayUpdate方法不會(huì)執(zhí)行,直到所有緩沖區(qū)均通過setDataBuffer方法設(shè)置。如果有參數(shù)需要調(diào)用setXXX方法賦值,可以調(diào)用setMaxIterations和setMaxParamSize方法,以及addIteration方法。具體如下:

  1. char fruits[][BUF_SIZE] = {“Apples”, “Oranges”, “Bananas”};   
  2. ub2 fruitLen[3];   
  3. for( int j=0; j<3; j++ )   
  4. {   
  5. fruitLen[j] = strlen( fruits[j] ) + 1; //include the null   
  6. }   
  7. stmt->setMaxIterations(3);   
  8. //setDataBuffer only needs to be executed once   
  9. //while all the other variables need to be set for each iteration   
  10. stmt->setDataBuffer( 1, fruits, OCCI_SQLT_STR, sizeof(fruits[0]),   
  11. fruitLen );   
  12. stmt->setInt(2, 3); //Apple’s quantity   
  13. stmt->addIteration();   
  14. stmt->setInt(2, 4); //Orange’s quantity   
  15. stmt->addIteration();   
  16. stmt->setInt(2, 1); //Banana’s quantity   
  17. //execute the iterative update   
  18. stmt->executeUpdate(3);  

  • 使用合適的Accessors和字符集

對操作的列使用合適的setXXX和getXXX方法,而非統(tǒng)一作為string處理,可以省去不必要的轉(zhuǎn)換。
在NLS_LANG環(huán)境設(shè)置中使用合適的字符集,以避免獲取字符串時(shí)不必要的字符集轉(zhuǎn)換。

自動(dòng)提交模式
由于所有的SQL DML都是在事務(wù)中執(zhí)行,所以需要確認(rèn)所有的DML??梢愿鶕?jù)具體情況使用“Connection::commit”和“Connection::rollback”方法?!癝tatement::setAutoCommit”方法可以用來確認(rèn)其后的每條語句。使用該方法可節(jié)省網(wǎng)絡(luò)傳輸時(shí)間。

  1. //code with AutoCommit   
  2. //transaction 1   
  3. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Apples”,3));   
  4. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Oranges”,4));   
  5. stmt->setAutoCommit( TRUE );   
  6. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Bananas”,1));   
  7. stmt->setAutoCommit( FALSE );   
  8. //transaction 2   
  9. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Apples”,5));   
  10. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Oranges”,6));   
  11. stmt->setAutoCommit( TRUE );   
  12. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Bananas”,2));   
  13. stmt->setAutoCommit( FALSE );  

這與下面的語句是等價(jià)的,但是2次網(wǎng)絡(luò)傳輸,每個(gè)事務(wù)1次

  1. //code without AutoCommit   
  2. //transaction 1   
  3. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Apples”,3));   
  4. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Oranges”,4));   
  5. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Bananas”,1));   
  6. conn->commit();   
  7. //transaction 2   
  8. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Apples”,5));   
  9. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Oranges”,6));   
  10. stmt->executeUpdate(“INSERT INTO fruit_basket_tab VALUES(“Bananas”,2));   
  11. conn->commit();  

建議AutoCommit只在每個(gè)事務(wù)的最后一條SQL語句前面使用。

  • 結(jié)果集對象的優(yōu)化
結(jié)果集作為請求的響應(yīng)返回??梢允褂胣ext和status方法處理結(jié)果集:

  1. ResultSet* rs = stmt->executeQuery( “SELECT * FROM fruit_basket_tab” );   
  2. ResultSet::Status stat = rs->status(); //status is DATA_AVAILABLE   
  3. while( rs->next() ) { //process data }  
  4. setPrefetchRowCount and setPrefetchMemorySize  

雖然rs->next()每次只能返回一行,但是可以在一次網(wǎng)絡(luò)中預(yù)取多行放到客戶端的緩存中。使用類Statement的setPrefetchRowCount方法和setPrefetchMemorySize方法,每次可以取得不止一行。上例優(yōu)化后如下:

stmt->setPrefetchRowCount( 3 ); 
ResultSet* rs = stmt->executeQuery( “SELECT * FROM fruit_basket_tab” ); 
while ( rs->next() ) { //process data }
使用上述代碼,在一次網(wǎng)絡(luò)通信中就能取得3條記錄。默認(rèn)情形中,預(yù)取功能是啟用的,每次多取一條。要想關(guān)閉預(yù)取功能,必須同時(shí)調(diào)用方法setPrefetchRowCount和setPrefetchMemorySize,參數(shù)為0。如果兩個(gè)setPrefetchXXX方法都被調(diào)用了,那么實(shí)際預(yù)取的數(shù)目是這兩個(gè)方法參數(shù)中較小的那個(gè)。

setMaxColumnSize
當(dāng)取得的結(jié)果中有些列較大時(shí),可以使用ResultSet::setMaxColumnSize方法限制從指定的列可以獲取多少數(shù)據(jù)。當(dāng)只對部分?jǐn)?shù)據(jù)感興趣或者緩存大小有限時(shí),這就有用了。

ResultSet *rs = stmt->executeQuery( “SELECT description FROM 
fruit_basket_tab” ); 
//want only first 80 characters from the description column 
rs->setMaxColumnSize( 1, 80 );
  • 關(guān)閉結(jié)果集
當(dāng)對結(jié)果集的處理結(jié)束后,調(diào)用Statement::closeResultSet方法手動(dòng)強(qiáng)制關(guān)閉,這樣數(shù)據(jù)庫和OCCI的使用的資源就不必等待自動(dòng)釋放。

  • 終止Statement
最后,為了確保沒有內(nèi)存泄漏,并關(guān)閉相關(guān)的服務(wù)器端的游標(biāo),需要釋放所有的statement對象。

conn->terminateStatement( stmt );


參考資料
Using OCCI: Best Practices
http://www.stanford.edu/dept/itss/docs/oracle/10gR2/appdev.102/b14294/performance.htm

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Linux下的Oracle C 編程(OCCI)
轉(zhuǎn):c ?Oracle?OCCI?編程
occi tricks
通過OCCI連接oracle(C++)
ResultSet詳解
vs 2008 開發(fā)環(huán)境 oralce occi開發(fā)配置
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服