VC++实现批量大容量快速插入SqlServer数据库

1. 概述

使用c++访问数据库的方法很多,由于我访问的是sqlserver数据库,于是上MSDN查了一下有哪些访问技术,主要有以下几种:
  • ODBC  
  • OLEDB
  • ADO
ADO是OLEDB的封装,使用起来比OLEDB方便。由于ADO比OLEDB多了一层,其速度可能不及OLEDB,所以就不考虑ADO了。
ODBC访问sqlserver有一个好处,可以在linux上使用。linux上可以使用FreeTDS作为sqlserver的ODBC驱动。OLEDB则只能在windows上运行。

1.1 ODBC(Open Database Connectivity)

ODBC是微软弄出来的一个可以访问各种数据库的接口。ODBC存在时间比较长,是一个比较稳定的接口。它既然能够访问各种接口,所以它是一个最小公共集的接口。这个接口里面可能会缺少某些数据库的特定功能。
ODBC只是一个接口,想要使用ODBC必须提供驱动。 sqlserver 提供SQL Server Native Client ODBC driver来支持ODBC接口。

1.2 OLEDB

OLEDB是一组基于COM的接口。OLEDB提供统一的接口,访问各种形式的数据。说到OLEDB就必须提交两个概念: consumer(使用接口的程序)、provider(接口的实现者)。OLEDB是定义一组接口,每个数据库供应商如果要是自己的数据库能通过OLEDB访问,就必须提供OLEDB Provider。
sqlserver的的provider是The SQL Server Native Client OLE DB provider。

2. 使用ODBC插入数据


ODBC插入数据速度快捷的方法主要有两种:

1. SQLBulkOperations 
[cpp]  view plain  copy
  1. #include <windows.h>  
  2. #include <sqlext.h>  
  3. #include <stdio.h>  
  4. #include <time.h>  
  5.   
  6. SQLHENV henv = NULL;  
  7. SQLHDBC hdbc = NULL;  
  8. SQLHSTMT hstmt = NULL;  
  9.   
  10. SQLRETURN retcode;  
  11. #define COUNT  (100000)  
  12.   
  13. #define ROW_ARRAY_SIZE 1000  
  14.   
  15. typedef struct{  
  16.     SQLINTEGER rec_num;  
  17.     SQLINTEGER rec_numInd;  
  18.     SQLCHAR date[9];  
  19.     SQLINTEGER dateInd;  
  20.     SQLCHAR time[9];  
  21.     SQLINTEGER timeInd;  
  22.     SQLCHAR reff[11];  
  23.     SQLINTEGER reffInd;  
  24.     SQLCHAR acc[11];  
  25.     SQLINTEGER accInd;  
  26.     SQLCHAR stock[7];  
  27.     SQLINTEGER stockInd;  
  28.     SQLCHAR bs[2];  
  29.     SQLINTEGER bsInd;  
  30.     SQLCHAR price[9];  
  31.     SQLINTEGER priceInd;  
  32.     SQLCHAR qty[9];  
  33.     SQLINTEGER qtyInd;  
  34.     SQLCHAR status[2];  
  35.     SQLINTEGER statusInd;  
  36.     SQLCHAR owflag[4];  
  37.     SQLINTEGER owflagInd;  
  38.     SQLCHAR ordrec[9];  
  39.     SQLINTEGER ordrecInd;  
  40.     SQLCHAR firmid[6];  
  41.     SQLINTEGER firmidInd;  
  42.     SQLCHAR branchid[6];  
  43.     SQLINTEGER branchidInd;  
  44.     SQLSCHAR checkord[16];  
  45.     SQLINTEGER checkordInd;  
  46. } ORDWTH;  
  47.   
  48. typedef struct{  
  49.     SQLINTEGER id;  
  50.     SQLCHAR date[20];  
  51.     SQLCHAR abbr[10];  
  52. //  
  53.     SQLINTEGER idInd;  
  54.     SQLINTEGER dateInd;  
  55.     SQLINTEGER abbrInd;  
  56. } Test;  
  57.   
  58. Test test_array[ROW_ARRAY_SIZE];  
  59.   
  60. ORDWTH  ordwth_array[ROW_ARRAY_SIZE];  
  61.   
  62. int rec_num = 1;  
  63.   
  64. void main()  
  65. {  
  66.     retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
  67.     retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);  
  68.   
  69.     retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);  
  70.     retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  71.   
  72.     retcode = SQLConnect(hdbc, (SQLCHAR*) "ctp2_lx", SQL_NTS, (SQLCHAR*)"sa", SQL_NTS, (SQLCHAR*)"123456", SQL_NTS);  
  73.     if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)  
  74.     {  
  75.           
  76.     }  
  77.     else  
  78.     {  
  79.         SQLCHAR msg[128];  
  80.         SQLCHAR state[128];  
  81.         SQLINTEGER error_id;  
  82.         SQLSMALLINT text;  
  83.         SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, state, &error_id, msg, 128, &text);  
  84.         printf("db connect fail, sqlstate=%s, errormsg=%s\n", state, msg);  
  85.         system("pause");  
  86.         return;  
  87.     }  
  88.   
  89.   
  90.     retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);  
  91.     printf("Inserting...\n");  
  92.   
  93.     time_t begin;  
  94.     time(&begin);  
  95.   
  96.   
  97.     //设定SQL_ATTR_ROW_ARRAY_SIZE属性,bulk的长度  
  98.     SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)ROW_ARRAY_SIZE, 0);  
  99.   
  100.     SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(ORDWTH), 0);  
  101.   
  102.     SQLUSMALLINT ParamStatusArray[ROW_ARRAY_SIZE] = { 0 };  
  103.     //设定状态数组  
  104.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, ParamStatusArray, 0);  
  105.     SQLINTEGER nBindOffset = 0;  
  106.     SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, (SQLPOINTER)&nBindOffset, 0);  
  107.   
  108.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_ROWVER, 0);  
  109.   
  110.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_DYNAMIC, 0);  
  111.   
  112.     //进行一次查询,得到result set  
  113.     retcode = SQLExecDirect(hstmt, (SQLCHAR*)"select rec_num, date, time, reff, acc, stock, bs, price, qty, status, owflag, ordrec, firmid, branchid, checkord  from ashare_ordwth", SQL_NTS);  
  114.     //retcode = SQLExecDirect(hstmt, (SQLCHAR*)"select id, date, abbr from test", SQL_NTS);  
  115.     retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);  
  116.   
  117.   
  118.     /*SQLBindCol(hstmt, 1, SQL_C_SHORT, &test_array[0].id, 0, &test_array[0].idInd); 
  119.     SQLBindCol(hstmt, 2, SQL_C_CHAR, &test_array[0].date, 20, &test_array[0].dateInd); 
  120.     SQLBindCol(hstmt, 3, SQL_C_CHAR, &test_array[0].abbr, 10, &test_array[0].abbrInd);*/  
  121.   
  122.     retcode = SQLBindCol(hstmt, 1, SQL_C_LONG, &ordwth_array[0].rec_num, 0, &ordwth_array[0].rec_numInd);  
  123.     SQLBindCol(hstmt, 2, SQL_C_CHAR, &ordwth_array[0].date, sizeof(ordwth_array[0].date), &ordwth_array[0].dateInd);  
  124.     SQLBindCol(hstmt, 3, SQL_C_CHAR, &ordwth_array[0].time, sizeof(ordwth_array[0].time), &ordwth_array[0].timeInd);  
  125.     SQLBindCol(hstmt, 4, SQL_C_CHAR, &ordwth_array[0].reff, sizeof(ordwth_array[0].reff), &ordwth_array[0].reffInd);  
  126.     SQLBindCol(hstmt, 5, SQL_C_CHAR, &ordwth_array[0].acc, sizeof(ordwth_array[0].acc), &ordwth_array[0].accInd);  
  127.     SQLBindCol(hstmt, 6, SQL_C_CHAR, &ordwth_array[0].stock, sizeof(ordwth_array[0].stock), &ordwth_array[0].stockInd);  
  128.     SQLBindCol(hstmt, 7, SQL_C_CHAR, &ordwth_array[0].bs, sizeof(ordwth_array[0].bs), &ordwth_array[0].bsInd);  
  129.     SQLBindCol(hstmt, 8, SQL_C_CHAR, &ordwth_array[0].price, sizeof(ordwth_array[0].price), &ordwth_array[0].priceInd);  
  130.     SQLBindCol(hstmt, 9, SQL_C_CHAR, &ordwth_array[0].qty, sizeof(ordwth_array[0].qty), &ordwth_array[0].qtyInd);  
  131.     SQLBindCol(hstmt, 10, SQL_C_CHAR, &ordwth_array[0].status, sizeof(ordwth_array[0].status), &ordwth_array[0].statusInd);  
  132.     SQLBindCol(hstmt, 11, SQL_C_CHAR, &ordwth_array[0].owflag, sizeof(ordwth_array[0].owflag), &ordwth_array[0].owflagInd);  
  133.     SQLBindCol(hstmt, 12, SQL_C_CHAR, &ordwth_array[0].ordrec, sizeof(ordwth_array[0].ordrec), &ordwth_array[0].ordrecInd);  
  134.     SQLBindCol(hstmt, 13, SQL_C_CHAR, &ordwth_array[0].firmid, sizeof(ordwth_array[0].firmid), &ordwth_array[0].firmidInd);  
  135.     SQLBindCol(hstmt, 14, SQL_C_CHAR, &ordwth_array[0].branchid, sizeof(ordwth_array[0].branchid), &ordwth_array[0].branchidInd);  
  136.     SQLBindCol(hstmt, 15, SQL_C_BINARY, &ordwth_array[0].checkord, sizeof(ordwth_array[0].checkord), &ordwth_array[0].checkordInd);  
  137.   
  138.     //关闭auto commit  
  139.     SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER);  
  140.   
  141.     for (int j = 0; j < COUNT / ROW_ARRAY_SIZE; j++)  
  142.     {  
  143.         for (int i = 0; i < ROW_ARRAY_SIZE; i++)  
  144.         {  
  145.             ordwth_array[i].rec_num = rec_num++;  
  146.             ordwth_array[i].ordrecInd = 0;  
  147.             strcpy((char*)ordwth_array[i].date, "20150120");  
  148.             ordwth_array[i].dateInd = SQL_NTS;  
  149.             strcpy((char*)ordwth_array[i].time, "13:20:10");  
  150.             ordwth_array[i].timeInd = SQL_NTS;  
  151.             strcpy((char*)ordwth_array[i].reff, "1234567890");  
  152.             ordwth_array[i].reffInd = SQL_NTS;  
  153.             strcpy((char*)ordwth_array[i].acc, "0000011111");  
  154.             ordwth_array[i].accInd = SQL_NTS;  
  155.             strcpy((char*)ordwth_array[i].stock, "123456");  
  156.             ordwth_array[i].stockInd = SQL_NTS;  
  157.             strcpy((char*)ordwth_array[i].bs, "B");  
  158.             ordwth_array[i].bsInd = SQL_NTS;  
  159.             strcpy((char*)ordwth_array[i].price, "1.000");  
  160.             ordwth_array[i].priceInd = SQL_NTS;  
  161.             strcpy((char*)ordwth_array[i].qty, "1000");  
  162.             ordwth_array[i].qtyInd = SQL_NTS;  
  163.             strcpy((char*)ordwth_array[i].status, "R");  
  164.             ordwth_array[i].statusInd = SQL_NTS;  
  165.             strcpy((char*)ordwth_array[i].owflag, "ORD");  
  166.             ordwth_array[i].owflagInd = SQL_NTS;  
  167.             strcpy((char*)ordwth_array[i].ordrec, "1");  
  168.             ordwth_array[i].ordrecInd = SQL_NTS;  
  169.             strcpy((char*)ordwth_array[i].firmid, "123");  
  170.             ordwth_array[i].firmidInd = SQL_NTS;  
  171.             strcpy((char*)ordwth_array[i].branchid, "20201");  
  172.             ordwth_array[i].branchidInd = SQL_NTS;  
  173.             ::memset(ordwth_array[i].checkord, 0, sizeof(ordwth_array[i].checkord));  
  174.             ordwth_array[i].checkordInd = sizeof(ordwth_array[i].checkord);  
  175.         }  
  176.   
  177.         //for (int i = 0; i < ROW_ARRAY_SIZE; i++)  
  178.         //{  
  179.         //  test_array[i].id = rec_num++;  
  180.         //  strcpy((char*)test_array[i].date, "20150120");  
  181.         //  strcpy((char*)test_array[i].abbr, "liuxing");  
  182.   
  183.         //  test_array[i].idInd = 0;  
  184.         //  test_array[i].dateInd = SQL_NTS;  
  185.         //  test_array[i].abbrInd = SQL_NTS;  
  186.         //}  
  187.   
  188.         retcode = SQLBulkOperations(hstmt, SQL_ADD);  
  189.   
  190.         if (retcode == SQL_ERROR)  
  191.         {  
  192.             SQLCHAR msg[128];  
  193.             SQLCHAR state[128];  
  194.             SQLINTEGER error_id;  
  195.             SQLSMALLINT text;  
  196.             SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, state, &error_id, msg, 128, &text);  
  197.             printf("db Insert fail, sqlstate=%s, errormsg=%s\n", state, msg);  
  198.             SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK);  
  199.             system("pause");  
  200.             return;  
  201.         }  
  202.         else if (retcode == SQL_SUCCESS_WITH_INFO)  
  203.         {  
  204.             SQLCHAR msg[128];  
  205.             SQLCHAR state[128];  
  206.             SQLINTEGER error_id;  
  207.             SQLSMALLINT text;  
  208.             SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, state, &error_id, msg, 128, &text);  
  209.             printf("warning msg=%s\n", msg);  
  210.         }  
  211.         retcode = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);  
  212.     }  
  213.   
  214.     time_t end;  
  215.     time(&end);  
  216.   
  217.     printf("Insert %d records in %lld seconds, average insert speed: %lld\n", COUNT, end - begin, COUNT / (end - begin));  
  218.     //printf("Insert %d records in %lld seconds\n", COUNT, end - begin);  
  219.     system("pause");  
  220.     return;  
  221. }  

使用这种方法,每秒钟只能查6000条记录。

2. 参数批量插入
[html]  view plain  copy
  1. #include <windows.h>  
  2. #include <sqlext.h>  
  3. #include <stdio.h>  
  4. #include <time.h>  
  5.   
  6. SQLHENV henv = NULL;  
  7. SQLHDBC hdbc = NULL;  
  8. SQLHSTMT hstmt = NULL;  
  9.   
  10. SQLRETURN retcode;  
  11. #define COUNT  (100000)  
  12.   
  13. #define ROW_ARRAY_SIZE 1000  
  14.   
  15. typedef struct{  
  16.     SQLINTEGER rec_num;  
  17.     SQLINTEGER rec_numInd;  
  18.     SQLCHAR date[9];  
  19.     SQLINTEGER dateInd;  
  20.     SQLCHAR time[9];  
  21.     SQLINTEGER timeInd;  
  22.     SQLCHAR reff[11];  
  23.     SQLINTEGER reffInd;  
  24.     SQLCHAR acc[11];  
  25.     SQLINTEGER accInd;  
  26.     SQLCHAR stock[7];  
  27.     SQLINTEGER stockInd;  
  28.     SQLCHAR bs[2];  
  29.     SQLINTEGER bsInd;  
  30.     SQLCHAR price[9];  
  31.     SQLINTEGER priceInd;  
  32.     SQLCHAR qty[9];  
  33.     SQLINTEGER qtyInd;  
  34.     SQLCHAR status[2];  
  35.     SQLINTEGER statusInd;  
  36.     SQLCHAR owflag[4];  
  37.     SQLINTEGER owflagInd;  
  38.     SQLCHAR ordrec[9];  
  39.     SQLINTEGER ordrecInd;  
  40.     SQLCHAR firmid[6];  
  41.     SQLINTEGER firmidInd;  
  42.     SQLCHAR branchid[6];  
  43.     SQLINTEGER branchidInd;  
  44.     SQLSCHAR checkord[16];  
  45.     SQLINTEGER checkordInd;  
  46. } ORDWTH;  
  47.   
  48. typedef struct{  
  49.     SQLINTEGER id;  
  50.     SQLCHAR date[20];  
  51.     SQLCHAR abbr[10];  
  52.     //  
  53.     SQLINTEGER idInd;  
  54.     SQLINTEGER dateInd;  
  55.     SQLLEN abbrInd;  
  56. } Test;  
  57.   
  58. Test test_array[ROW_ARRAY_SIZE];  
  59.   
  60. ORDWTH  ordwth_array[ROW_ARRAY_SIZE];  
  61.   
  62. int rec_num = 1;  
  63.   
  64. void main()  
  65. {  
  66.     retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);  
  67.     retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);  
  68.   
  69.     retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);  
  70.     retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);  
  71.   
  72.     retcode = SQLConnect(hdbc, (SQLCHAR*) "ctp2_lx", SQL_NTS, (SQLCHAR*)"sa", SQL_NTS, (SQLCHAR*)"123456", SQL_NTS);  
  73.     if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)  
  74.     {  
  75.   
  76.     }  
  77.     else  
  78.     {  
  79.         SQLCHAR msg[128];  
  80.         SQLCHAR state[128];  
  81.         SQLINTEGER error_id;  
  82.         SQLSMALLINT text;  
  83.         SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, state, &error_id, msg, 128, &text);  
  84.         printf("db connect fail, sqlstate=%s, errormsg=%s\n", state, msg);  
  85.         system("pause");  
  86.         return;  
  87.     }  
  88.   
  89.   
  90.     retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);  
  91.     printf("Inserting...\n");  
  92.   
  93.     time_t begin;  
  94.     time(&begin);  
  95.   
  96.   
  97.     //设定SQL_ATTR_ROW_ARRAY_SIZE属性,bulk的长度  
  98.     //SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)ROW_ARRAY_SIZE, 0);  
  99.   
  100.     SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(ORDWTH), 0);  
  101.   
  102.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_BIND_TYPE, (SQLPOINTER)sizeof(ORDWTH), SQL_IS_INTEGER);  
  103.   
  104.     //设定每次参数的数量  
  105.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)(long)ROW_ARRAY_SIZE, SQL_IS_INTEGER);  
  106.   
  107.     SQLUSMALLINT ParamStatusArray[ROW_ARRAY_SIZE] = { 0 };  
  108.     //设定状态数组  
  109.     retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, ParamStatusArray, 0);  
  110.     SQLINTEGER nBindOffset = 0;  
  111.     SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, (SQLPOINTER)&nBindOffset, 0);  
  112.   
  113.     //retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_ROWVER, 0);  
  114.   
  115.     //retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_DYNAMIC, 0);  
  116.   
  117.     SQLCHAR *sql = (SQLCHAR*)"Insert into ashare_ordwth(rec_num, date, time, reff, acc, stock, bs, price, qty, status, owflag, ordrec, firmid, branchid, checkord) Values(?, ?, ?, ?, ?,?,?, ?, ?, ?, ?, ?, ?, ?, ?)";  
  118.     //SQLCHAR *sql = (SQLCHAR*)"Insert into ashare_ordwth(rec_num) Values(?)";  
  119.   
  120.     SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, sizeof(ordwth_array[0].rec_num), 0, &ordwth_array[0].rec_num, sizeof(ordwth_array[0].rec_num), &ordwth_array[0].rec_numInd);  
  121.     SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].date) - 1, 0, &ordwth_array[0].date, sizeof(ordwth_array[0].date), &ordwth_array[0].dateInd);  
  122.     SQLBindParameter(hstmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].time) - 1, 0, &ordwth_array[0].time, sizeof(ordwth_array[0].time), &ordwth_array[0].timeInd);  
  123.     SQLBindParameter(hstmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].reff) - 1, 0, &ordwth_array[0].reff, sizeof(ordwth_array[0].reff), &ordwth_array[0].reffInd);  
  124.     SQLBindParameter(hstmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].acc) - 1, 0, &ordwth_array[0].acc, sizeof(ordwth_array[0].acc), &ordwth_array[0].accInd);  
  125.     SQLBindParameter(hstmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].stock) - 1, 0, &ordwth_array[0].stock, sizeof(ordwth_array[0].stock), &ordwth_array[0].stockInd);  
  126.     SQLBindParameter(hstmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].bs) - 1, 0, &ordwth_array[0].bs, sizeof(ordwth_array[0].bs), &ordwth_array[0].bsInd);  
  127.     SQLBindParameter(hstmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].price) - 1, 0, &ordwth_array[0].price, sizeof(ordwth_array[0].price), &ordwth_array[0].priceInd);  
  128.     SQLBindParameter(hstmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].qty) - 1, 0, &ordwth_array[0].qty, sizeof(ordwth_array[0].qty), &ordwth_array[0].qtyInd);  
  129.     SQLBindParameter(hstmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].status) - 1, 0, &ordwth_array[0].status, sizeof(ordwth_array[0].status), &ordwth_array[0].statusInd);  
  130.     SQLBindParameter(hstmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].owflag) - 1, 0, &ordwth_array[0].owflag, sizeof(ordwth_array[0].owflag), &ordwth_array[0].owflagInd);  
  131.     SQLBindParameter(hstmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].ordrec) - 1, 0, &ordwth_array[0].ordrec, sizeof(ordwth_array[0].ordrec), &ordwth_array[0].ordrecInd);  
  132.     SQLBindParameter(hstmt, 13, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].firmid) - 1, 0, &ordwth_array[0].firmid, sizeof(ordwth_array[0].firmid), &ordwth_array[0].firmidInd);  
  133.     SQLBindParameter(hstmt, 14, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(ordwth_array[0].branchid) - 1, 0, &ordwth_array[0].branchid, sizeof(ordwth_array[0].branchid), &ordwth_array[0].branchidInd);  
  134.     SQLBindParameter(hstmt, 15, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, sizeof(ordwth_array[0].checkord), 0, &ordwth_array[0].checkord, sizeof(ordwth_array[0].checkord), &ordwth_array[0].checkordInd);  
  135.   
  136.     SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, 0);  
  137.     retcode = SQLPrepare(hstmt, sql, SQL_NTS);  
  138.   
  139.     for (int j = 0; j < COUNT / ROW_ARRAY_SIZE; j++)  
  140.     {  
  141.         for (int i = 0; i < ROW_ARRAY_SIZE; i++)  
  142.         {  
  143.             ordwth_array[i].rec_num = rec_num++;  
  144.             ordwth_array[i].ordrecInd = 0;  
  145.             strcpy((char*)ordwth_array[i].date, "20150120");  
  146.             ordwth_array[i].dateInd = SQL_NTS;  
  147.             strcpy((char*)ordwth_array[i].time, "13:20:10");  
  148.             ordwth_array[i].timeInd = SQL_NTS;  
  149.             strcpy((char*)ordwth_array[i].reff, "1234567890");  
  150.             ordwth_array[i].reffInd = SQL_NTS;  
  151.             strcpy((char*)ordwth_array[i].acc, "0000011111");  
  152.             ordwth_array[i].accInd = SQL_NTS;  
  153.             strcpy((char*)ordwth_array[i].stock, "123456");  
  154.             ordwth_array[i].stockInd = SQL_NTS;  
  155.             strcpy((char*)ordwth_array[i].bs, "B");  
  156.             ordwth_array[i].bsInd = SQL_NTS;  
  157.             strcpy((char*)ordwth_array[i].price, "1.000");  
  158.             ordwth_array[i].priceInd = SQL_NTS;  
  159.             strcpy((char*)ordwth_array[i].qty, "1000");  
  160.             ordwth_array[i].qtyInd = SQL_NTS;  
  161.             strcpy((char*)ordwth_array[i].status, "R");  
  162.             ordwth_array[i].statusInd = SQL_NTS;  
  163.             strcpy((char*)ordwth_array[i].owflag, "ORD");  
  164.             ordwth_array[i].owflagInd = SQL_NTS;  
  165.             strcpy((char*)ordwth_array[i].ordrec, "1");  
  166.             ordwth_array[i].ordrecInd = SQL_NTS;  
  167.             strcpy((char*)ordwth_array[i].firmid, "123");  
  168.             ordwth_array[i].firmidInd = SQL_NTS;  
  169.             strcpy((char*)ordwth_array[i].branchid, "20201");  
  170.             ordwth_array[i].branchidInd = SQL_NTS;  
  171.             ::memset(ordwth_array[i].checkord, 0, sizeof(ordwth_array[i].checkord));  
  172.             ordwth_array[i].checkordInd = sizeof(ordwth_array[i].checkord);  
  173.         }  
  174.   
  175.         //执行语句  
  176.         retcode = SQLExecute(hstmt);  
  177.   
  178.         if (retcode == SQL_ERROR)  
  179.         {  
  180.             SQLCHAR msg[128];  
  181.             SQLCHAR state[128];  
  182.             SQLINTEGER error_id;  
  183.             SQLSMALLINT text;  
  184.             SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, state, &error_id, msg, 128, &text);  
  185.             printf("db Insert fail, sqlstate=%s, errormsg=%s\n", state, msg);  
  186.   
  187.             SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK);  
  188.   
  189.             system("pause");  
  190.             return;  
  191.         }  
  192.         else if (retcode == SQL_SUCCESS_WITH_INFO)  
  193.         {  
  194.             SQLCHAR msg[128];  
  195.             SQLCHAR state[128];  
  196.             SQLINTEGER error_id;  
  197.             SQLSMALLINT text;  
  198.             SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, state, &error_id, msg, 128, &text);  
  199.             printf("warning msg=%s\n", msg);  
  200.         }  
  201.   
  202.         SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);  
  203.     }  
  204.   
  205.     time_t end;  
  206.     time(&end);  
  207.   
  208.     printf("Insert %d records in %lld seconds, average insert speed: %lld\n", COUNT, end - begin, COUNT / (end - begin));  
  209.     //printf("Insert %d records in %lld seconds\n", COUNT, end - begin);  
  210.     system("pause");  
  211.     return;  
  212. }  

使用这种方法,每秒能插16000条记录。

3. 使用OLEDB插入数据


该例子包含两个文件:bulkcopy.h bulkcopy.cpp

bulkcopy.h
[cpp]  view plain  copy
  1. #define DBINITCONSTANTS  
  2. #define OLEDBVER 0x0250   // to include correct interfaces  
  3.   
  4. #include <oledb.h>  
  5. #include <oledberr.h>  
  6. #include <stdio.h>  
  7. #include <stddef.h>   // for offsetof  
  8. //#include <sqlncli.h>  
  9. #include "C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Include\sqlncli.h"  
  10.   
  11. // @type UWORD    | 2 byte unsigned integer.  
  12. typedef unsigned short UWORD;  
  13.   
  14. // @type SDWORD   | 4 byte signed integer.  
  15. typedef signed long SDWORD;  
  16.   
  17. //委托表数据结构体  
  18. struct Data  
  19. {  
  20.     SDWORD rec_num_len;   // Length of data (not space allocated).  
  21.     DWORD rec_num_status;   // Status of column.  
  22.     int rec_num;  
  23.   
  24.     SDWORD date_len;  
  25.     DWORD date_status;  
  26.     char date[9];  
  27.   
  28.     SDWORD time_len;  
  29.     DWORD time_status;  
  30.     char time[9];  
  31.   
  32.     SDWORD reff_len;  
  33.     DWORD reff_status;  
  34.     char reff[11];  
  35.   
  36.     SDWORD acc_len;  
  37.     DWORD acc_status;  
  38.     char acc[11];  
  39.   
  40.     SDWORD stock_len;  
  41.     DWORD stock_status;  
  42.     char stock[7];  
  43.   
  44.     SDWORD bs_len;  
  45.     DWORD bs_status;  
  46.     char bs[2];  
  47.   
  48.     SDWORD price_len;  
  49.     DWORD price_status;  
  50.     char price[9];  
  51.   
  52.     SDWORD qty_len;  
  53.     DWORD qty_status;  
  54.     char qty[9];  
  55.   
  56.     SDWORD status_len;  
  57.     DWORD status_status;  
  58.     char status[2];  
  59.   
  60.     SDWORD owflag_len;  
  61.     DWORD owflag_status;  
  62.     char owflag[4];  
  63.   
  64.     SDWORD ordrec_len;  
  65.     DWORD ordrec_status;  
  66.     char ordrec[9];  
  67.   
  68.     SDWORD firmid_len;  
  69.     DWORD firmid_status;  
  70.     char firmid[6];  
  71.   
  72.     SDWORD branchid_len;  
  73.     DWORD branchid_status;  
  74.     char branchid[6];  
  75.   
  76.     SDWORD checkord_len;  
  77.     DWORD checkord_status;  
  78.     BYTE checkord[16];  
  79.   
  80. };  
  81.   
  82. //委托表每列的数据类型  
  83. DBTYPEENUM col_type[15] = {  
  84.     DBTYPE_I4,  
  85.     DBTYPE_STR,  
  86.     DBTYPE_STR,  
  87.     DBTYPE_STR,  
  88.     DBTYPE_STR,  
  89.     DBTYPE_STR,  
  90.     DBTYPE_STR,  
  91.     DBTYPE_STR,  
  92.     DBTYPE_STR,  
  93.     DBTYPE_STR,  
  94.     DBTYPE_STR,  
  95.     DBTYPE_STR,  
  96.     DBTYPE_STR,  
  97.     DBTYPE_STR,  
  98.     DBTYPE_BYTES  
  99. };  
  100.   
  101. //委托表没列的数据长度  
  102. DBBYTEOFFSET col_len[15] = {  
  103.     sizeof(int),  
  104.     9,  
  105.     9,  
  106.     11,  
  107.     11,  
  108.     7,  
  109.     2,  
  110.     9,  
  111.     9,  
  112.     2,  
  113.     4,  
  114.     9,  
  115.     6,  
  116.     6,  
  117.     16  
  118. };  
  119.   
  120. // How to lay out each column in memory.  
  121. struct COLUMNDATA {  
  122.     SDWORD idLen;   // Length of data (not space allocated).  
  123.     DWORD idStatus;   // Status of column.  
  124.     int id;   // Store data here as a variant.  
  125.     SDWORD dateLen;  
  126.     DWORD dateStatus;  
  127.     char date[21];  
  128. };  
  129.   
  130.   
  131. //函数申明  
  132. void set_bindings();  
  133.   
  134. //一个绑定  
  135. void set_bind(DBBINDING &binding, int col, DBBYTEOFFSET len_offset, DBBYTEOFFSET status_offset, DBBYTEOFFSET value_offset, DBLENGTH len, DBTYPE type);  
  136.   
  137. // Given an ICommand pointer, properties, and query, a rowsetpointer is returned.  
  138. HRESULT CreateSessionCommand(DBPROPSET* rgPropertySets, ULONG ulcPropCount, CLSID clsidProv);  
  139.   
  140. // Use to set properties and execute a given query.  
  141. HRESULT ExecuteQuery(IDBCreateCommand* pIDBCreateCommand,  
  142.     WCHAR* pwszQuery,  
  143.     DBPROPSET* rgPropertySets,  
  144.     ULONG ulcPropCount,  
  145.     LONG* pcRowsAffected,  
  146.     IRowset** ppIRowset,  
  147.     BOOL fSuccessOnly = TRUE);  
  148.   
  149.   
  150. void DumpErrorInfo(IUnknown* pObjectWithError, REFIID IID_InterfaceWithError);  
  151.   
  152. // Use to set up options for call to IDBInitialize::Initialize.  
  153. void SetupOption(DBPROPID PropID, WCHAR *wszVal, DBPROP * pDBProp);  
  154.   
  155. // Sets fastload property on/off for session.  
  156. HRESULT SetFastLoadProperty(BOOL fSet);  
  157.   
  158. HRESULT FastInsertData();  

bulkcopy.cpp
[cpp]  view plain  copy
  1. #include "bulkcopy.h"  
  2. #include <time.h>  
  3.   
  4. #define COUNT  1000000  
  5. #define ROW_SIZE  1000  
  6.   
  7. #define COLUMN_ALIGNVAL 8  
  8. #define ROUND_UP(Size, Amount)(((DWORD)(Size) + ((Amount)-1)) & ~((Amount)-1))  
  9.   
  10. WCHAR g_wszTable[] = L"ashare_ordwth";  
  11. //WCHAR g_wszTable[] = L"test";  
  12. WCHAR g_strTestLOC[100] = L"172.19.124.72";  
  13. WCHAR g_strTestDBName[] = L"ctp2_lx";  
  14. const UWORD g_cOPTION = 5;  
  15. const UWORD MAXPROPERTIES = 5;  
  16. const ULONG DEFAULT_CBMAXLENGTH = 20;  
  17. IMalloc* g_pIMalloc = NULL;  
  18. IDBInitialize* g_pIDBInitialize = NULL;  
  19.   
  20. int rec_num = 1;  
  21.   
  22.   
  23. //binding数组  
  24. DBBINDING g_bindings[15];  
  25.   
  26. int main() {  
  27.     HRESULT hr = NOERROR;  
  28.     HRESULT hr2 = NOERROR;  
  29.   
  30.     // OLE initialized?  
  31.     BOOL fInitialized = FALSE;  
  32.   
  33.     // One property set for initializing.  
  34.     DBPROPSET rgPropertySets[1];  
  35.   
  36.     // Properties within above property set.  
  37.     DBPROP rgDBProperties[g_cOPTION];  
  38.   
  39.     IDBCreateCommand* pIDBCreateCommand = NULL;  
  40.     IRowset* pIRowset = NULL;  
  41.     DBPROPSET* rgProperties = NULL;  
  42.     IAccessor* pIAccessor = NULL;  
  43.   
  44.     // Basic initialization.  
  45.     if (FAILED(CoInitialize(NULL)))  
  46.         goto cleanup;  
  47.     else  
  48.         fInitialized = TRUE;  
  49.   
  50.     hr = CoGetMalloc(MEMCTX_TASK, &g_pIMalloc);  
  51.     if ((!g_pIMalloc) || FAILED(hr))  
  52.         goto cleanup;  
  53.   
  54.     // Set up property set for call to IDBInitialize in CreateSessionCommand.  
  55.     rgPropertySets[0].rgProperties = rgDBProperties;  
  56.     rgPropertySets[0].cProperties = g_cOPTION;  
  57.     rgPropertySets[0].guidPropertySet = DBPROPSET_DBINIT;  
  58.   
  59.     SetupOption(DBPROP_INIT_CATALOG, L"ctp2_lx", &rgDBProperties[0]);  
  60.     //SetupOption(DBPROP_INIT_DATASOURCE, L"ctp2_lx", &rgDBProperties[0]);  
  61.   
  62.     //SetupOption(DBPROP_AUTH_INTEGRATED, L"SSPI", &rgDBProperties[1]);  
  63.   
  64.     SetupOption(DBPROP_INIT_DATASOURCE, L"172.19.124.72", &rgDBProperties[1]);  
  65.     //SetupOption(DBPROP_INIT_LOCATION, L"172.19.124.72", &rgDBProperties[2]);  
  66.     //密码  
  67.     SetupOption(DBPROP_AUTH_PASSWORD, L"123456", &rgDBProperties[3]);  
  68.     //用户名  
  69.     SetupOption(DBPROP_AUTH_USERID, L"sa", &rgDBProperties[4]);  
  70.   
  71.     if (!SUCCEEDED(hr = CreateSessionCommand(rgPropertySets, 1, SQLNCLI_CLSID)))  
  72.         goto cleanup;  
  73.   
  74.     time_t begin;  
  75.     time(&begin);  
  76.     // Get IRowsetFastLoad and insert data into IRFLTable.  
  77.       
  78.     if (FAILED(hr = FastInsertData()))  
  79.             goto cleanup;  
  80.   
  81.     time_t end;  
  82.     time(&end);  
  83.     printf("Elapse Time= [%lld]\n", end - begin);  
  84.   
  85. cleanup:  
  86.     // Release memory.  
  87.     if (rgProperties && rgProperties->rgProperties)  
  88.         delete[](rgProperties->rgProperties);  
  89.     if (rgProperties)  
  90.         delete[]rgProperties;  
  91.     if (pIDBCreateCommand)  
  92.         pIDBCreateCommand->Release();  
  93.   
  94.     if (pIAccessor)  
  95.         pIAccessor->Release();  
  96.   
  97.     if (pIRowset)  
  98.         pIRowset->Release();  
  99.     if (g_pIMalloc)  
  100.         g_pIMalloc->Release();  
  101.   
  102.     if (g_pIDBInitialize) {  
  103.         hr2 = g_pIDBInitialize->Uninitialize();  
  104.         if (FAILED(hr2))  
  105.             printf("Uninitialize failed\n");  
  106.     }  
  107.   
  108.     if (fInitialized)  
  109.         CoUninitialize();  
  110.   
  111.     if (SUCCEEDED(hr))  
  112.         printf("Test completed successfully.\n\n");  
  113.     else  
  114.         printf("Test failed.\n\n");  
  115.   
  116.     system("pause");  
  117. }  
  118.   
  119. void set_bindings()  
  120. {  
  121.     set_bind(g_bindings[0], 1, offsetof(Data, rec_num_len), offsetof(Data, rec_num_status), offsetof(Data, rec_num), col_len[0], col_type[0]);  
  122.     set_bind(g_bindings[1], 2, offsetof(Data, date_len), offsetof(Data, date_status), offsetof(Data, date), col_len[1], col_type[1]);  
  123.     set_bind(g_bindings[2], 3, offsetof(Data, time_len), offsetof(Data, time_status), offsetof(Data, time), col_len[2], col_type[2]);  
  124.     set_bind(g_bindings[3], 4, offsetof(Data, reff_len), offsetof(Data, reff_status), offsetof(Data, reff), col_len[3], col_type[3]);  
  125.     set_bind(g_bindings[4], 5, offsetof(Data, acc_len), offsetof(Data, acc_status), offsetof(Data, acc), col_len[4], col_type[4]);  
  126.     set_bind(g_bindings[5], 6, offsetof(Data, stock_len), offsetof(Data, stock_status), offsetof(Data, stock), col_len[5], col_type[5]);  
  127.     set_bind(g_bindings[6], 7, offsetof(Data, bs_len), offsetof(Data, bs_status), offsetof(Data, bs), col_len[6], col_type[6]);  
  128.     set_bind(g_bindings[7], 8, offsetof(Data, price_len), offsetof(Data, price_status), offsetof(Data, price), col_len[7], col_type[7]);  
  129.     set_bind(g_bindings[8], 9, offsetof(Data, qty_len), offsetof(Data, qty_status), offsetof(Data, qty), col_len[8], col_type[8]);  
  130.     set_bind(g_bindings[9], 10, offsetof(Data, status_len), offsetof(Data, status_status), offsetof(Data, status), col_len[9], col_type[9]);  
  131.     set_bind(g_bindings[10], 11, offsetof(Data, owflag_len), offsetof(Data, owflag_status), offsetof(Data, owflag), col_len[10], col_type[10]);  
  132.     set_bind(g_bindings[11], 12, offsetof(Data, ordrec_len), offsetof(Data, ordrec_status), offsetof(Data, ordrec), col_len[11], col_type[11]);  
  133.     set_bind(g_bindings[12], 13, offsetof(Data, firmid_len), offsetof(Data, firmid_status), offsetof(Data, firmid), col_len[12], col_type[12]);  
  134.     set_bind(g_bindings[13], 14, offsetof(Data, branchid_len), offsetof(Data, branchid_status), offsetof(Data, branchid), col_len[13], col_type[13]);  
  135.     set_bind(g_bindings[14], 15, offsetof(Data, checkord_len), offsetof(Data, checkord_status), offsetof(Data, checkord), col_len[14], col_type[14]);  
  136. }  
  137.   
  138. void set_bind(DBBINDING &binding, int col, DBBYTEOFFSET len_offset, DBBYTEOFFSET status_offset, DBBYTEOFFSET value_offset, DBLENGTH len, DBTYPE type)  
  139. {  
  140.     binding.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;  
  141.     binding.iOrdinal = col;  
  142.     binding.pTypeInfo = NULL;  
  143.     binding.obValue = value_offset;  
  144.     binding.obLength = len_offset;  
  145.     binding.obStatus = status_offset;  
  146.     binding.cbMaxLen = len;   // Size of varchar column.  
  147.     binding.pTypeInfo = NULL;  
  148.     binding.pObject = NULL;  
  149.     binding.pBindExt = NULL;  
  150.     binding.dwFlags = 0;  
  151.     binding.eParamIO = DBPARAMIO_NOTPARAM;  
  152.     binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;  
  153.     binding.bPrecision = 0;  
  154.     binding.bScale = 0;  
  155.     binding.wType = type;  
  156. }  
  157.   
  158.   
  159.   
  160.   
  161. //插入委托表  
  162. HRESULT FastInsertData() {  
  163.     HRESULT hr = E_FAIL;  
  164.     HRESULT hr2 = E_FAIL;  
  165.     DBID TableID;  
  166.   
  167.     IDBCreateSession* pIDBCreateSession = NULL;  
  168.     IOpenRowset* pIOpenRowsetFL = NULL;  
  169.     IRowsetFastLoad* pIFastLoad = NULL;  
  170.   
  171.     IAccessor* pIAccessor = NULL;  
  172.     HACCESSOR hAccessor = 0;  
  173.     DBBINDSTATUS bindingStatus[15] = { 0 };  
  174.   
  175.   
  176.     TableID.uName.pwszName = NULL;  
  177.     LONG i = 0;  
  178.     void* pData = NULL;  
  179.   
  180.     TableID.eKind = DBKIND_NAME;  
  181.     // if ( !(TableID.uName.pwszName = new WCHAR[wcslen(g_wszTable) + 2]) )  
  182.     LPOLESTR x = TableID.uName.pwszName = new WCHAR[wcslen(g_wszTable) + 2];  
  183.     if (!x)  
  184.         return E_FAIL;  
  185.     wcsncpy_s(TableID.uName.pwszName, wcslen(g_wszTable) + 2, g_wszTable, wcslen(g_wszTable) + 1);  
  186.     TableID.uName.pwszName[wcslen(g_wszTable) + 1] = (WCHAR)NULL;  
  187.   
  188.     // Get the fastload pointer.  
  189.     if (FAILED(hr = SetFastLoadProperty(TRUE)))  
  190.         goto cleanup;  
  191.   
  192.     if (FAILED(hr =  
  193.         g_pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void **)&pIDBCreateSession)))  
  194.         goto cleanup;  
  195.   
  196.     if (FAILED(hr =  
  197.         pIDBCreateSession->CreateSession(NULL, IID_IOpenRowset, (IUnknown **)&pIOpenRowsetFL)))  
  198.         goto cleanup;  
  199.   
  200.     // Get IRowsetFastLoad initialized to use the test table.  
  201.     if (FAILED(hr =  
  202.         pIOpenRowsetFL->OpenRowset(NULL,  
  203.         &TableID,  
  204.         NULL,  
  205.         IID_IRowsetFastLoad,  
  206.         0,  
  207.         NULL,  
  208.         (LPUNKNOWN *)&pIFastLoad)))  
  209.         goto cleanup;  
  210.   
  211.     set_bindings();  
  212.   
  213.     if (FAILED(hr =  
  214.         pIFastLoad->QueryInterface(IID_IAccessor, (void **)&pIAccessor)))  
  215.         return hr;  
  216.   
  217.     if (FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,  
  218.         15,  
  219.         g_bindings,  
  220.         ROUND_UP(sizeof(Data), COLUMN_ALIGNVAL),  
  221.         &hAccessor,  
  222.         bindingStatus)))  
  223.         return hr;  
  224.   
  225.     Data *datas = new Data[COUNT];  
  226.     for (int i = 0; i < COUNT; i++)  
  227.     {  
  228.         datas[i].rec_num_len = col_len[0];  
  229.         datas[i].date_len = col_len[1];  
  230.         datas[i].time_len = col_len[2];  
  231.         datas[i].reff_len = col_len[3];  
  232.         datas[i].acc_len = col_len[4];  
  233.         datas[i].stock_len = col_len[5];  
  234.         datas[i].bs_len = col_len[6];  
  235.         datas[i].price_len = col_len[7];  
  236.         datas[i].qty_len = col_len[8];  
  237.         datas[i].status_len = col_len[9];  
  238.         datas[i].owflag_len = col_len[10];  
  239.         datas[i].ordrec_len = col_len[11];  
  240.         datas[i].firmid_len = col_len[12];  
  241.         datas[i].branchid_len = col_len[13];  
  242.         datas[i].checkord_len = col_len[14];  
  243.   
  244.         datas[i].rec_num_status = 0;  
  245.         datas[i].date_status = 0;  
  246.         datas[i].time_status = 0;  
  247.         datas[i].reff_status = 0;  
  248.         datas[i].acc_status = 0;  
  249.         datas[i].stock_status = 0;  
  250.         datas[i].bs_status = 0;  
  251.         datas[i].price_status = 0;  
  252.         datas[i].qty_status = 0;  
  253.         datas[i].status_status = 0;  
  254.         datas[i].owflag_status = 0;  
  255.         datas[i].ordrec_status = 0;  
  256.         datas[i].firmid_status = 0;  
  257.         datas[i].branchid_status = 0;  
  258.         datas[i].checkord_status = 0;  
  259.     }  
  260.   
  261.     for (int i = 0; i < COUNT; i++)  
  262.     {  
  263.             datas[i].rec_num = rec_num++;  
  264.             strncpy(datas[i].date, "20150120", col_len[1]);  
  265.             strncpy(datas[i].time, "13:20:10", col_len[2]);  
  266.             strncpy(datas[i].reff, "1234567890", col_len[3]);  
  267.             strncpy(datas[i].acc, "0000011111", col_len[4]);  
  268.             strncpy(datas[i].stock, "123456", col_len[5]);  
  269.             strncpy(datas[i].bs, "B", col_len[6]);  
  270.             strncpy(datas[i].price, "1.000", col_len[7]);  
  271.             strncpy(datas[i].qty, "1000", col_len[8]);  
  272.             strncpy(datas[i].status, "R", col_len[9]);  
  273.             strncpy(datas[i].owflag, "ORD", col_len[10]);  
  274.             strncpy(datas[i].ordrec, "1", col_len[11]);  
  275.             strncpy(datas[i].firmid, "123", col_len[12]);  
  276.             strncpy(datas[i].branchid, "20201", col_len[13]);  
  277.             memset(datas[i].checkord, 0, col_len[14]);  
  278.   
  279.             if (FAILED(hr = pIFastLoad->InsertRow(hAccessor, &datas[i])))  
  280.             {  
  281.   
  282.                 DumpErrorInfo(pIFastLoad, IID_ISQLServerErrorInfo);  
  283.   
  284.                 goto cleanup;  
  285.             }  
  286.   }
  287.         if (FAILED(hr = pIFastLoad->Commit(TRUE)))  
  288.         {  
  289.             DumpErrorInfo(pIFastLoad, IID_ISQLServerErrorInfo);  
  290.   
  291.             printf("Error on IRFL::Commit\n");  
  292.         }  
  293.     
  294. cleanup:  
  295.     if (FAILED(hr2 = SetFastLoadProperty(FALSE)))  
  296.         printf("SetFastLoadProperty(FALSE) failed with %x", hr2);  
  297.   
  298.     if (pIAccessor && hAccessor)  
  299.     if (FAILED(pIAccessor->ReleaseAccessor(hAccessor, NULL)))  
  300.         hr = E_FAIL;  
  301.   
  302.     if (pIAccessor)  
  303.         pIAccessor->Release();  
  304.   
  305.     if (pIFastLoad)  
  306.         pIFastLoad->Release();  
  307.   
  308.     if (pIOpenRowsetFL)  
  309.         pIOpenRowsetFL->Release();  
  310.   
  311.     if (pIDBCreateSession)  
  312.         pIDBCreateSession->Release();  
  313.   
  314.     if (TableID.uName.pwszName)  
  315.         delete[]TableID.uName.pwszName;  
  316.   
  317.     delete[] datas;  
  318.   
  319.     return hr;  
  320. }  
  321.   
  322. HRESULT SetFastLoadProperty(BOOL fSet) {  
  323.     HRESULT hr = S_OK;  
  324.     IDBProperties* pIDBProps = NULL;  
  325.     DBPROP rgProps[1];  
  326.     DBPROPSET PropSet;  
  327.   
  328.     VariantInit(&rgProps[0].vValue);  
  329.   
  330.     rgProps[0].dwOptions = DBPROPOPTIONS_REQUIRED;  
  331.     rgProps[0].colid = DB_NULLID;  
  332.     rgProps[0].vValue.vt = VT_BOOL;  
  333.     rgProps[0].dwPropertyID = SSPROP_ENABLEFASTLOAD;  
  334.   
  335.     if (fSet == TRUE)  
  336.         rgProps[0].vValue.boolVal = VARIANT_TRUE;  
  337.     else  
  338.         rgProps[0].vValue.boolVal = VARIANT_FALSE;  
  339.   
  340.     PropSet.rgProperties = rgProps;  
  341.     PropSet.cProperties = 1;  
  342.     PropSet.guidPropertySet = DBPROPSET_SQLSERVERDATASOURCE;  
  343.   
  344.     if (SUCCEEDED(hr = g_pIDBInitialize->QueryInterface(IID_IDBProperties, (LPVOID *)&pIDBProps)))  
  345.         hr = pIDBProps->SetProperties(1, &PropSet);  
  346.   
  347.     VariantClear(&rgProps[0].vValue);  
  348.   
  349.     if (pIDBProps)  
  350.         pIDBProps->Release();  
  351.   
  352.     return hr;  
  353. }  
  354.   
  355. HRESULT CreateSessionCommand(DBPROPSET* rgPropertySets,// @parm [in] property sets  
  356.     ULONG ulcPropCount,   // @parm [in] count of prop sets.  
  357.     CLSID clsidProv) {  // @parm [in] Provider CLSID.  
  358.   
  359.     HRESULT hr = NOERROR;  
  360.     IDBCreateSession* pIDBCreateSession = NULL;  
  361.     IDBProperties* pIDBProperties = NULL;  
  362.     UWORD i = 0, j = 0;   // indexes.  
  363.   
  364.     if (ulcPropCount && !rgPropertySets) {  
  365.         hr = E_INVALIDARG;  
  366.         return hr;  
  367.     }  
  368.   
  369.     if (!SUCCEEDED(hr = CoCreateInstance(clsidProv,  
  370.         NULL, CLSCTX_INPROC_SERVER,  
  371.         IID_IDBInitialize,  
  372.         (void **)&g_pIDBInitialize)))  
  373.         goto CLEANUP;  
  374.   
  375.     if (!SUCCEEDED(hr = g_pIDBInitialize->QueryInterface(IID_IDBProperties,  
  376.         (void **)&pIDBProperties)))  
  377.         goto CLEANUP;  
  378.   
  379.     if (!SUCCEEDED(hr = pIDBProperties->SetProperties(ulcPropCount, rgPropertySets)))  
  380.         goto CLEANUP;  
  381.   
  382.     if (!SUCCEEDED(hr = g_pIDBInitialize->Initialize())) {  
  383.   
  384.         printf("Call to initialize failed.\n");  
  385.         goto CLEANUP;  
  386.     }  
  387.   
  388. CLEANUP:  
  389.     if (pIDBProperties)  
  390.         pIDBProperties->Release();  
  391.     if (pIDBCreateSession)  
  392.         pIDBCreateSession->Release();  
  393.   
  394.     for (i = 0; i < ulcPropCount; i++)  
  395.     for (j = 0; j < rgPropertySets[i].cProperties; j++)  
  396.         VariantClear(&(rgPropertySets[i].rgProperties[j]).vValue);  
  397.     return hr;  
  398. }  
  399.   
  400. void SetupOption(DBPROPID PropID, WCHAR *wszVal, DBPROP * pDBProp) {  
  401.     pDBProp->dwPropertyID = PropID;  
  402.     pDBProp->dwOptions = DBPROPOPTIONS_REQUIRED;  
  403.     pDBProp->colid = DB_NULLID;  
  404.     pDBProp->vValue.vt = VT_BSTR;  
  405.     pDBProp->vValue.bstrVal = SysAllocStringLen(wszVal, wcslen(wszVal));  
  406. }  
  407.   
  408. // DumpErrorInfo queries SQLOLEDB error interfaces, retrieving available  
  409. // status or error information.  
  410. void DumpErrorInfo  
  411. (  
  412. IUnknown* pObjectWithError,  
  413. REFIID IID_InterfaceWithError  
  414. )  
  415. {  
  416.   
  417.     // Interfaces used in the example.  
  418.     IErrorInfo*             pIErrorInfoAll = NULL;  
  419.     IErrorInfo*             pIErrorInfoRecord = NULL;  
  420.     IErrorRecords*          pIErrorRecords = NULL;  
  421.     ISupportErrorInfo*      pISupportErrorInfo = NULL;  
  422.     ISQLErrorInfo*          pISQLErrorInfo = NULL;  
  423.     ISQLServerErrorInfo*    pISQLServerErrorInfo = NULL;  
  424.   
  425.     // Number of error records.  
  426.     ULONG                   nRecs;  
  427.     ULONG                   nRec;  
  428.   
  429.     // Basic error information from GetBasicErrorInfo.  
  430.     ERRORINFO               errorinfo;  
  431.   
  432.     // IErrorInfo values.  
  433.     BSTR                    bstrDescription;  
  434.     BSTR                    bstrSource;  
  435.   
  436.     // ISQLErrorInfo parameters.  
  437.     BSTR                    bstrSQLSTATE;  
  438.     LONG                    lNativeError;  
  439.   
  440.     // ISQLServerErrorInfo parameter pointers.  
  441.     SSERRORINFO*            pSSErrorInfo = NULL;  
  442.     OLECHAR*                pSSErrorStrings = NULL;  
  443.   
  444.     // Hard-code an American English locale for the example.  
  445.     DWORD                   MYLOCALEID = 0x0409;  
  446.   
  447.     // Only ask for error information if the interface supports  
  448.     // it.  
  449.     if (FAILED(pObjectWithError->QueryInterface(IID_ISupportErrorInfo,  
  450.         (void**)&pISupportErrorInfo)))  
  451.     {  
  452.         wprintf_s(L"SupportErrorErrorInfo interface not supported");  
  453.         return;  
  454.     }  
  455.     if (FAILED(pISupportErrorInfo->  
  456.         InterfaceSupportsErrorInfo(IID_InterfaceWithError)))  
  457.     {  
  458.         wprintf_s(L"InterfaceWithError interface not supported");  
  459.         return;  
  460.     }  
  461.   
  462.     // Do not test the return of GetErrorInfo. It can succeed and return  
  463.     // a NULL pointer in pIErrorInfoAll. Simply test the pointer.  
  464.     GetErrorInfo(0, &pIErrorInfoAll);  
  465.   
  466.     if (pIErrorInfoAll != NULL)  
  467.     {  
  468.         // Test to see if it's a valid OLE DB IErrorInfo interface   
  469.         // exposing a list of records.  
  470.         if (SUCCEEDED(pIErrorInfoAll->QueryInterface(IID_IErrorRecords,  
  471.             (void**)&pIErrorRecords)))  
  472.         {  
  473.             pIErrorRecords->GetRecordCount(&nRecs);  
  474.   
  475.             // Within each record, retrieve information from each  
  476.             // of the defined interfaces.  
  477.             for (nRec = 0; nRec < nRecs; nRec++)  
  478.             {  
  479.                 // From IErrorRecords, get the HRESULT and a reference  
  480.                 // to the ISQLErrorInfo interface.  
  481.                 pIErrorRecords->GetBasicErrorInfo(nRec, &errorinfo);  
  482.                 pIErrorRecords->GetCustomErrorObject(nRec,  
  483.                     IID_ISQLErrorInfo, (IUnknown**)&pISQLErrorInfo);  
  484.   
  485.                 // Display the HRESULT, then use the ISQLErrorInfo.  
  486.                 wprintf_s(L"HRESULT:\t%#X\n", errorinfo.hrError);  
  487.   
  488.                 if (pISQLErrorInfo != NULL)  
  489.                 {  
  490.                     pISQLErrorInfo->GetSQLInfo(&bstrSQLSTATE,  
  491.                         &lNativeError);  
  492.   
  493.                     // Display the SQLSTATE and native error values.  
  494.                     wprintf_s(L"SQLSTATE:\t%s\nNative Error:\t%ld\n",  
  495.                         bstrSQLSTATE, lNativeError);  
  496.   
  497.                     // SysFree BSTR references.  
  498.                     SysFreeString(bstrSQLSTATE);  
  499.   
  500.                     // Get the ISQLServerErrorInfo interface from  
  501.                     // ISQLErrorInfo before releasing the reference.  
  502.                     pISQLErrorInfo->QueryInterface(  
  503.                         IID_ISQLServerErrorInfo,  
  504.                         (void**)&pISQLServerErrorInfo);  
  505.   
  506.                     pISQLErrorInfo->Release();  
  507.                 }  
  508.   
  509.                 // Test to ensure the reference is valid, then  
  510.                 // get error information from ISQLServerErrorInfo.  
  511.                 if (pISQLServerErrorInfo != NULL)  
  512.                 {  
  513.                     pISQLServerErrorInfo->GetErrorInfo(&pSSErrorInfo,  
  514.                         &pSSErrorStrings);  
  515.   
  516.                     // ISQLServerErrorInfo::GetErrorInfo succeeds  
  517.                     // even when it has nothing to return. Test the  
  518.                     // pointers before using.  
  519.                     if (pSSErrorInfo)  
  520.                     {  
  521.                         // Display the state and severity from the  
  522.                         // returned information. The error message comes  
  523.                         // from IErrorInfo::GetDescription.  
  524.                         wprintf_s(L"Error state:\t%d\nSeverity:\t%d\n",  
  525.                             pSSErrorInfo->bState,  
  526.                             pSSErrorInfo->bClass);  
  527.   
  528.                         // IMalloc::Free needed to release references  
  529.                         // on returned values. For the example, assume  
  530.                         // the g_pIMalloc pointer is valid.  
  531.                         g_pIMalloc->Free(pSSErrorStrings);  
  532.                         g_pIMalloc->Free(pSSErrorInfo);  
  533.                     }  
  534.   
  535.                     pISQLServerErrorInfo->Release();  
  536.                 }  
  537.   
  538.                 if (SUCCEEDED(pIErrorRecords->GetErrorInfo(nRec,  
  539.                     MYLOCALEID, &pIErrorInfoRecord)))  
  540.                 {  
  541.                     // Get the source and description (error message)  
  542.                     // from the record's IErrorInfo.  
  543.                     pIErrorInfoRecord->GetSource(&bstrSource);  
  544.                     pIErrorInfoRecord->GetDescription(&bstrDescription);  
  545.   
  546.                     if (bstrSource != NULL)  
  547.                     {  
  548.                         wprintf_s(L"Source:\t\t%s\n", bstrSource);  
  549.                         SysFreeString(bstrSource);  
  550.                     }  
  551.                     if (bstrDescription != NULL)  
  552.                     {  
  553.                         wprintf_s(L"Error message:\t%s\n",  
  554.                             bstrDescription);  
  555.                         SysFreeString(bstrDescription);  
  556.                     }  
  557.   
  558.                     pIErrorInfoRecord->Release();  
  559.                 }  
  560.             }  
  561.   
  562.             pIErrorRecords->Release();  
  563.         }  
  564.         else  
  565.         {  
  566.             // IErrorInfo is valid; get the source and  
  567.             // description to see what it is.  
  568.             pIErrorInfoAll->GetSource(&bstrSource);  
  569.             pIErrorInfoAll->GetDescription(&bstrDescription);  
  570.   
  571.             if (bstrSource != NULL)  
  572.             {  
  573.                 wprintf_s(L"Source:\t\t%s\n", bstrSource);  
  574.                 SysFreeString(bstrSource);  
  575.             }  
  576.             if (bstrDescription != NULL)  
  577.             {  
  578.                 wprintf_s(L"Error message:\t%s\n", bstrDescription);  
  579.                 SysFreeString(bstrDescription);  
  580.             }  
  581.         }  
  582.   
  583.         pIErrorInfoAll->Release();  
  584.     }  
  585.     else  
  586.     {  
  587.         wprintf_s(L"GetErrorInfo failed.");  
  588.     }  
  589.   
  590.     pISupportErrorInfo->Release();  
  591.   
  592.     return;  
  593. }  

使用上面方法,每秒钟可以插入3万多条记录。
OLEDB的接口确实有点繁琐~有时候读了好多遍MSDN上的接口说明,也执行不正确。


原标题:《c++ 访问sqlserver数据库,插入速度优化》

来源:http://blog.csdn.net/frank_liuxing/article/details/43231233


另一参考文章:

《Bulk Copy Data Using IRowsetFastLoad (OLE DB)》

https://docs.microsoft.com/zh-cn/sql/relational-databases/native-client-ole-db-how-to/bulk-copy-data-using-irowsetfastload-ole-db


《使用 IROWSETFASTLOAD 和 ISEQUENTIALSTREAM 将 BLOB 数据发送到 SQL SERVER (OLE DB)》

https://technet.microsoft.com/zh-cn/library/ff878198(de-de,SQL.120).aspx


《利用Native Client OLEDB 11 高效率地对SQL SERVER 进行查询和插入操作》

http://www.cnblogs.com/SamRichard/p/5550050.html



  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
vc链接SQL Server数据库的步骤如下: 1. 首先,在VC项目中添加与SQL Server数据库连接相关的头文件和库文件。头文件主要包括"stdafx.h"和"sql.h",库文件主要包括"odbc32.lib"和"odbccp32.lib"。 2. 在VC项目中创建一个数据库连接对象,可以使用ODBC(Open Database Connectivity)来进行操作。首先定义一个数据库连接句柄,例如"HDBC hconn",并使用SQLAllocHandle函数创建一个数据库连接。示例代码如下: HDBC hconn; SQLAllocHandle(SQL_HANDLE_DBC, SQL_NULL_HANDLE, &hconn); 3. 设置连接属性。可以使用SQLSetConnectAttr函数为连接设置不同的属性,例如设置连接超时时长,示例代码如下: SQLSetConnectAttr(hconn, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, SQL_IS_INTEGER); 4. 使用SQLConnect函数连接到SQL Server数据库。为SQLConnect函数提供正确的连接参数,包括服务器名、用户名、密码等信息。示例代码如下: SQLConnect(hconn, L"server_name", SQL_NTS, L"user_name", SQL_NTS, L"password", SQL_NTS); 5. 连接成功后,可以使用SQLExecDirect函数执行SQL语句。通过组合SQL语句来进行数据库的增删改查操作。示例代码如下: SQLExecDirect(hconn, L"SELECT * FROM table_name", SQL_NTS); 6. 执行完毕后,使用SQLDisconnect函数断开与SQL Server数据库的连接。示例代码如下: SQLDisconnect(hconn); 以上步骤是通过ODBC连接SQL Server数据库的基本流程,通过编写相应的代码并进行调试,就可以实现VC与SQL Server数据库的连接和操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值