c++ 訪問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 
#include <windows.h>
#include <sqlext.h>
#include <stdio.h>
#include <time.h>

SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLHSTMT hstmt = NULL;

SQLRETURN retcode;
#define COUNT  (100000)

#define ROW_ARRAY_SIZE 1000

typedef struct{
	SQLINTEGER rec_num;
	SQLINTEGER rec_numInd;
	SQLCHAR date[9];
	SQLINTEGER dateInd;
	SQLCHAR time[9];
	SQLINTEGER timeInd;
	SQLCHAR reff[11];
	SQLINTEGER reffInd;
	SQLCHAR acc[11];
	SQLINTEGER accInd;
	SQLCHAR stock[7];
	SQLINTEGER stockInd;
	SQLCHAR bs[2];
	SQLINTEGER bsInd;
	SQLCHAR price[9];
	SQLINTEGER priceInd;
	SQLCHAR qty[9];
	SQLINTEGER qtyInd;
	SQLCHAR status[2];
	SQLINTEGER statusInd;
	SQLCHAR owflag[4];
	SQLINTEGER owflagInd;
	SQLCHAR ordrec[9];
	SQLINTEGER ordrecInd;
	SQLCHAR firmid[6];
	SQLINTEGER firmidInd;
	SQLCHAR branchid[6];
	SQLINTEGER branchidInd;
	SQLSCHAR checkord[16];
	SQLINTEGER checkordInd;
} ORDWTH;

typedef struct{
	SQLINTEGER id;
	SQLCHAR date[20];
	SQLCHAR abbr[10];
//
	SQLINTEGER idInd;
	SQLINTEGER dateInd;
	SQLINTEGER abbrInd;
} Test;

Test test_array[ROW_ARRAY_SIZE];

ORDWTH  ordwth_array[ROW_ARRAY_SIZE];

int rec_num = 1;

void main()
{
	retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);

	retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
	retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

	retcode = SQLConnect(hdbc, (SQLCHAR*) "ctp2_lx", SQL_NTS, (SQLCHAR*)"sa", SQL_NTS, (SQLCHAR*)"123456", SQL_NTS);
	if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
	{
		
	}
	else
	{
		SQLCHAR msg[128];
		SQLCHAR state[128];
		SQLINTEGER error_id;
		SQLSMALLINT text;
		SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, state, &error_id, msg, 128, &text);
		printf("db connect fail, sqlstate=%s, errormsg=%s\n", state, msg);
		system("pause");
		return;
	}


	retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
	printf("Inserting...\n");

	time_t begin;
	time(&begin);


	//設定SQL_ATTR_ROW_ARRAY_SIZE屬性,bulk的長度
	SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)ROW_ARRAY_SIZE, 0);

	SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(ORDWTH), 0);

	SQLUSMALLINT ParamStatusArray[ROW_ARRAY_SIZE] = { 0 };
	//設定狀態數組
	retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, ParamStatusArray, 0);
	SQLINTEGER nBindOffset = 0;
	SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, (SQLPOINTER)&nBindOffset, 0);

	retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_ROWVER, 0);

	retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_DYNAMIC, 0);

	//進行一次查詢,得到result set
	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);
	//retcode = SQLExecDirect(hstmt, (SQLCHAR*)"select id, date, abbr from test", SQL_NTS);
	retcode = SQLFetchScroll(hstmt, SQL_FETCH_NEXT, 0);


	/*SQLBindCol(hstmt, 1, SQL_C_SHORT, &test_array[0].id, 0, &test_array[0].idInd);
	SQLBindCol(hstmt, 2, SQL_C_CHAR, &test_array[0].date, 20, &test_array[0].dateInd);
	SQLBindCol(hstmt, 3, SQL_C_CHAR, &test_array[0].abbr, 10, &test_array[0].abbrInd);*/

	retcode = SQLBindCol(hstmt, 1, SQL_C_LONG, &ordwth_array[0].rec_num, 0, &ordwth_array[0].rec_numInd);
	SQLBindCol(hstmt, 2, SQL_C_CHAR, &ordwth_array[0].date, sizeof(ordwth_array[0].date), &ordwth_array[0].dateInd);
	SQLBindCol(hstmt, 3, SQL_C_CHAR, &ordwth_array[0].time, sizeof(ordwth_array[0].time), &ordwth_array[0].timeInd);
	SQLBindCol(hstmt, 4, SQL_C_CHAR, &ordwth_array[0].reff, sizeof(ordwth_array[0].reff), &ordwth_array[0].reffInd);
	SQLBindCol(hstmt, 5, SQL_C_CHAR, &ordwth_array[0].acc, sizeof(ordwth_array[0].acc), &ordwth_array[0].accInd);
	SQLBindCol(hstmt, 6, SQL_C_CHAR, &ordwth_array[0].stock, sizeof(ordwth_array[0].stock), &ordwth_array[0].stockInd);
	SQLBindCol(hstmt, 7, SQL_C_CHAR, &ordwth_array[0].bs, sizeof(ordwth_array[0].bs), &ordwth_array[0].bsInd);
	SQLBindCol(hstmt, 8, SQL_C_CHAR, &ordwth_array[0].price, sizeof(ordwth_array[0].price), &ordwth_array[0].priceInd);
	SQLBindCol(hstmt, 9, SQL_C_CHAR, &ordwth_array[0].qty, sizeof(ordwth_array[0].qty), &ordwth_array[0].qtyInd);
	SQLBindCol(hstmt, 10, SQL_C_CHAR, &ordwth_array[0].status, sizeof(ordwth_array[0].status), &ordwth_array[0].statusInd);
	SQLBindCol(hstmt, 11, SQL_C_CHAR, &ordwth_array[0].owflag, sizeof(ordwth_array[0].owflag), &ordwth_array[0].owflagInd);
	SQLBindCol(hstmt, 12, SQL_C_CHAR, &ordwth_array[0].ordrec, sizeof(ordwth_array[0].ordrec), &ordwth_array[0].ordrecInd);
	SQLBindCol(hstmt, 13, SQL_C_CHAR, &ordwth_array[0].firmid, sizeof(ordwth_array[0].firmid), &ordwth_array[0].firmidInd);
	SQLBindCol(hstmt, 14, SQL_C_CHAR, &ordwth_array[0].branchid, sizeof(ordwth_array[0].branchid), &ordwth_array[0].branchidInd);
	SQLBindCol(hstmt, 15, SQL_C_BINARY, &ordwth_array[0].checkord, sizeof(ordwth_array[0].checkord), &ordwth_array[0].checkordInd);

	//關閉auto commit
	SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_IS_INTEGER);

	for (int j = 0; j < COUNT / ROW_ARRAY_SIZE; j++)
	{
		for (int i = 0; i < ROW_ARRAY_SIZE; i++)
		{
			ordwth_array[i].rec_num = rec_num++;
			ordwth_array[i].ordrecInd = 0;
			strcpy((char*)ordwth_array[i].date, "20150120");
			ordwth_array[i].dateInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].time, "13:20:10");
			ordwth_array[i].timeInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].reff, "1234567890");
			ordwth_array[i].reffInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].acc, "0000011111");
			ordwth_array[i].accInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].stock, "123456");
			ordwth_array[i].stockInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].bs, "B");
			ordwth_array[i].bsInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].price, "1.000");
			ordwth_array[i].priceInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].qty, "1000");
			ordwth_array[i].qtyInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].status, "R");
			ordwth_array[i].statusInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].owflag, "ORD");
			ordwth_array[i].owflagInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].ordrec, "1");
			ordwth_array[i].ordrecInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].firmid, "123");
			ordwth_array[i].firmidInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].branchid, "20201");
			ordwth_array[i].branchidInd = SQL_NTS;
			::memset(ordwth_array[i].checkord, 0, sizeof(ordwth_array[i].checkord));
			ordwth_array[i].checkordInd = sizeof(ordwth_array[i].checkord);
		}

		//for (int i = 0; i < ROW_ARRAY_SIZE; i++)
		//{
		//	test_array[i].id = rec_num++;
		//	strcpy((char*)test_array[i].date, "20150120");
		//	strcpy((char*)test_array[i].abbr, "liuxing");

		//	test_array[i].idInd = 0;
		//	test_array[i].dateInd = SQL_NTS;
		//	test_array[i].abbrInd = SQL_NTS;
		//}

		retcode = SQLBulkOperations(hstmt, SQL_ADD);

		if (retcode == SQL_ERROR)
		{
			SQLCHAR msg[128];
			SQLCHAR state[128];
			SQLINTEGER error_id;
			SQLSMALLINT text;
			SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, state, &error_id, msg, 128, &text);
			printf("db Insert fail, sqlstate=%s, errormsg=%s\n", state, msg);
			SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK);
			system("pause");
			return;
		}
		else if (retcode == SQL_SUCCESS_WITH_INFO)
		{
			SQLCHAR msg[128];
			SQLCHAR state[128];
			SQLINTEGER error_id;
			SQLSMALLINT text;
			SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, state, &error_id, msg, 128, &text);
			printf("warning msg=%s\n", msg);
		}
		retcode = SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
	}

	time_t end;
	time(&end);

	printf("Insert %d records in %lld seconds, average insert speed: %lld\n", COUNT, end - begin, COUNT / (end - begin));
	//printf("Insert %d records in %lld seconds\n", COUNT, end - begin);
	system("pause");
	return;
}

使用這種方法,每秒鐘只能查6000條記錄。

2. 參數批量插入
#include <windows.h>
#include <sqlext.h>
#include <stdio.h>
#include <time.h>

SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLHSTMT hstmt = NULL;

SQLRETURN retcode;
#define COUNT  (100000)

#define ROW_ARRAY_SIZE 1000

typedef struct{
	SQLINTEGER rec_num;
	SQLINTEGER rec_numInd;
	SQLCHAR date[9];
	SQLINTEGER dateInd;
	SQLCHAR time[9];
	SQLINTEGER timeInd;
	SQLCHAR reff[11];
	SQLINTEGER reffInd;
	SQLCHAR acc[11];
	SQLINTEGER accInd;
	SQLCHAR stock[7];
	SQLINTEGER stockInd;
	SQLCHAR bs[2];
	SQLINTEGER bsInd;
	SQLCHAR price[9];
	SQLINTEGER priceInd;
	SQLCHAR qty[9];
	SQLINTEGER qtyInd;
	SQLCHAR status[2];
	SQLINTEGER statusInd;
	SQLCHAR owflag[4];
	SQLINTEGER owflagInd;
	SQLCHAR ordrec[9];
	SQLINTEGER ordrecInd;
	SQLCHAR firmid[6];
	SQLINTEGER firmidInd;
	SQLCHAR branchid[6];
	SQLINTEGER branchidInd;
	SQLSCHAR checkord[16];
	SQLINTEGER checkordInd;
} ORDWTH;

typedef struct{
	SQLINTEGER id;
	SQLCHAR date[20];
	SQLCHAR abbr[10];
	//
	SQLINTEGER idInd;
	SQLINTEGER dateInd;
	SQLLEN abbrInd;
} Test;

Test test_array[ROW_ARRAY_SIZE];

ORDWTH  ordwth_array[ROW_ARRAY_SIZE];

int rec_num = 1;

void main()
{
	retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
	retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER*)SQL_OV_ODBC3, 0);

	retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
	retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

	retcode = SQLConnect(hdbc, (SQLCHAR*) "ctp2_lx", SQL_NTS, (SQLCHAR*)"sa", SQL_NTS, (SQLCHAR*)"123456", SQL_NTS);
	if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
	{

	}
	else
	{
		SQLCHAR msg[128];
		SQLCHAR state[128];
		SQLINTEGER error_id;
		SQLSMALLINT text;
		SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, state, &error_id, msg, 128, &text);
		printf("db connect fail, sqlstate=%s, errormsg=%s\n", state, msg);
		system("pause");
		return;
	}


	retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
	printf("Inserting...\n");

	time_t begin;
	time(&begin);


	//設定SQL_ATTR_ROW_ARRAY_SIZE屬性,bulk的長度
	//SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)ROW_ARRAY_SIZE, 0);

	SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER)sizeof(ORDWTH), 0);

	retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_PARAM_BIND_TYPE, (SQLPOINTER)sizeof(ORDWTH), SQL_IS_INTEGER);

	//設定每次參數的數量
	retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)(long)ROW_ARRAY_SIZE, SQL_IS_INTEGER);

	SQLUSMALLINT ParamStatusArray[ROW_ARRAY_SIZE] = { 0 };
	//設定狀態數組
	retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_STATUS_PTR, ParamStatusArray, 0);
	SQLINTEGER nBindOffset = 0;
	SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, (SQLPOINTER)&nBindOffset, 0);

	//retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER)SQL_CONCUR_ROWVER, 0);

	//retcode = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_DYNAMIC, 0);

	SQLCHAR *sql = (SQLCHAR*)"Insert into ashare_ordwth(rec_num, date, time, reff, acc, stock, bs, price, qty, status, owflag, ordrec, firmid, branchid, checkord) Values(?, ?, ?, ?, ?,?,?, ?, ?, ?, ?, ?, ?, ?, ?)";
	//SQLCHAR *sql = (SQLCHAR*)"Insert into ashare_ordwth(rec_num) Values(?)";

	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);
    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);
    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);
	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);
	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);
	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);
	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);
	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);
	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);
	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);
	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);
	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);
	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);
	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);
	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);

	SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, 0);
	retcode = SQLPrepare(hstmt, sql, SQL_NTS);

	for (int j = 0; j < COUNT / ROW_ARRAY_SIZE; j++)
	{
		for (int i = 0; i < ROW_ARRAY_SIZE; i++)
		{
			ordwth_array[i].rec_num = rec_num++;
			ordwth_array[i].ordrecInd = 0;
			strcpy((char*)ordwth_array[i].date, "20150120");
			ordwth_array[i].dateInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].time, "13:20:10");
			ordwth_array[i].timeInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].reff, "1234567890");
			ordwth_array[i].reffInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].acc, "0000011111");
			ordwth_array[i].accInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].stock, "123456");
			ordwth_array[i].stockInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].bs, "B");
			ordwth_array[i].bsInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].price, "1.000");
			ordwth_array[i].priceInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].qty, "1000");
			ordwth_array[i].qtyInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].status, "R");
			ordwth_array[i].statusInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].owflag, "ORD");
			ordwth_array[i].owflagInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].ordrec, "1");
			ordwth_array[i].ordrecInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].firmid, "123");
			ordwth_array[i].firmidInd = SQL_NTS;
			strcpy((char*)ordwth_array[i].branchid, "20201");
			ordwth_array[i].branchidInd = SQL_NTS;
			::memset(ordwth_array[i].checkord, 0, sizeof(ordwth_array[i].checkord));
			ordwth_array[i].checkordInd = sizeof(ordwth_array[i].checkord);
		}

		//執行語句
		retcode = SQLExecute(hstmt);

		if (retcode == SQL_ERROR)
		{
			SQLCHAR msg[128];
			SQLCHAR state[128];
			SQLINTEGER error_id;
			SQLSMALLINT text;
			SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, state, &error_id, msg, 128, &text);
			printf("db Insert fail, sqlstate=%s, errormsg=%s\n", state, msg);

			SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK);

			system("pause");
			return;
		}
		else if (retcode == SQL_SUCCESS_WITH_INFO)
		{
			SQLCHAR msg[128];
			SQLCHAR state[128];
			SQLINTEGER error_id;
			SQLSMALLINT text;
			SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, state, &error_id, msg, 128, &text);
			printf("warning msg=%s\n", msg);
		}

		SQLEndTran(SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
	}

	time_t end;
	time(&end);

	printf("Insert %d records in %lld seconds, average insert speed: %lld\n", COUNT, end - begin, COUNT / (end - begin));
	//printf("Insert %d records in %lld seconds\n", COUNT, end - begin);
	system("pause");
	return;
}

使用這種方法,每秒能插16000條記錄。

3. 使用OLEDB插入數據


該例子包含兩個文件:bulkcopy.h bulkcopy.cpp

bulkcopy.h
#define DBINITCONSTANTS
#define OLEDBVER 0x0250   // to include correct interfaces

#include <oledb.h>
#include <oledberr.h>
#include <stdio.h>
#include <stddef.h>   // for offsetof
//#include <sqlncli.h>
#include "C:\Program Files (x86)\Microsoft SQL Server\100\SDK\Include\sqlncli.h"

// @type UWORD    | 2 byte unsigned integer.
typedef unsigned short UWORD;

// @type SDWORD   | 4 byte signed integer.
typedef signed long SDWORD;

//委託表數據結構體
struct Data
{
	SDWORD rec_num_len;   // Length of data (not space allocated).
	DWORD rec_num_status;   // Status of column.
	int rec_num;

	SDWORD date_len;
	DWORD date_status;
	char date[9];

	SDWORD time_len;
	DWORD time_status;
	char time[9];

	SDWORD reff_len;
	DWORD reff_status;
	char reff[11];

	SDWORD acc_len;
	DWORD acc_status;
	char acc[11];

	SDWORD stock_len;
	DWORD stock_status;
	char stock[7];

	SDWORD bs_len;
	DWORD bs_status;
	char bs[2];

	SDWORD price_len;
	DWORD price_status;
	char price[9];

	SDWORD qty_len;
	DWORD qty_status;
	char qty[9];

	SDWORD status_len;
	DWORD status_status;
	char status[2];

	SDWORD owflag_len;
	DWORD owflag_status;
	char owflag[4];

	SDWORD ordrec_len;
	DWORD ordrec_status;
	char ordrec[9];

	SDWORD firmid_len;
	DWORD firmid_status;
	char firmid[6];

	SDWORD branchid_len;
	DWORD branchid_status;
	char branchid[6];

	SDWORD checkord_len;
	DWORD checkord_status;
	BYTE checkord[16];

};

//委託表每列的數據類型
DBTYPEENUM col_type[15] = {
	DBTYPE_I4,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_STR,
	DBTYPE_BYTES
};

//委託表沒列的數據長度
DBBYTEOFFSET col_len[15] = {
	sizeof(int),
	9,
	9,
	11,
	11,
	7,
	2,
	9,
	9,
	2,
	4,
	9,
	6,
	6,
	16
};

// How to lay out each column in memory.
struct COLUMNDATA {
	SDWORD idLen;   // Length of data (not space allocated).
	DWORD idStatus;   // Status of column.
	int id;   // Store data here as a variant.
	SDWORD dateLen;
	DWORD dateStatus;
	char date[21];
};


//函數申明
void set_bindings();

//一個綁定
void set_bind(DBBINDING &binding, int col, DBBYTEOFFSET len_offset, DBBYTEOFFSET status_offset, DBBYTEOFFSET value_offset, DBLENGTH len, DBTYPE type);

// Given an ICommand pointer, properties, and query, a rowsetpointer is returned.
HRESULT CreateSessionCommand(DBPROPSET* rgPropertySets, ULONG ulcPropCount, CLSID clsidProv);

// Use to set properties and execute a given query.
HRESULT ExecuteQuery(IDBCreateCommand* pIDBCreateCommand,
	WCHAR* pwszQuery,
	DBPROPSET* rgPropertySets,
	ULONG ulcPropCount,
	LONG* pcRowsAffected,
	IRowset** ppIRowset,
	BOOL fSuccessOnly = TRUE);


void DumpErrorInfo(IUnknown* pObjectWithError, REFIID IID_InterfaceWithError);

// Use to set up options for call to IDBInitialize::Initialize.
void SetupOption(DBPROPID PropID, WCHAR *wszVal, DBPROP * pDBProp);

// Sets fastload property on/off for session.
HRESULT SetFastLoadProperty(BOOL fSet);

HRESULT FastInsertData();

bulkcopy.cpp
#include "bulkcopy.h"
#include <time.h>

#define COUNT  1000000
#define ROW_SIZE  1000

#define COLUMN_ALIGNVAL 8
#define ROUND_UP(Size, Amount)(((DWORD)(Size) + ((Amount)-1)) & ~((Amount)-1))

WCHAR g_wszTable[] = L"ashare_ordwth";
//WCHAR g_wszTable[] = L"test";
WCHAR g_strTestLOC[100] = L"172.19.124.72";
WCHAR g_strTestDBName[] = L"ctp2_lx";
const UWORD g_cOPTION = 5;
const UWORD MAXPROPERTIES = 5;
const ULONG DEFAULT_CBMAXLENGTH = 20;
IMalloc* g_pIMalloc = NULL;
IDBInitialize* g_pIDBInitialize = NULL;

int rec_num = 1;


//binding數組
DBBINDING g_bindings[15];

int main() {
	HRESULT hr = NOERROR;
	HRESULT hr2 = NOERROR;

	// OLE initialized?
	BOOL fInitialized = FALSE;

	// One property set for initializing.
	DBPROPSET rgPropertySets[1];

	// Properties within above property set.
	DBPROP rgDBProperties[g_cOPTION];

	IDBCreateCommand* pIDBCreateCommand = NULL;
	IRowset* pIRowset = NULL;
	DBPROPSET* rgProperties = NULL;
	IAccessor* pIAccessor = NULL;

	// Basic initialization.
	if (FAILED(CoInitialize(NULL)))
		goto cleanup;
	else
		fInitialized = TRUE;

	hr = CoGetMalloc(MEMCTX_TASK, &g_pIMalloc);
	if ((!g_pIMalloc) || FAILED(hr))
		goto cleanup;

	// Set up property set for call to IDBInitialize in CreateSessionCommand.
	rgPropertySets[0].rgProperties = rgDBProperties;
	rgPropertySets[0].cProperties = g_cOPTION;
	rgPropertySets[0].guidPropertySet = DBPROPSET_DBINIT;

	SetupOption(DBPROP_INIT_CATALOG, L"ctp2_lx", &rgDBProperties[0]);
	//SetupOption(DBPROP_INIT_DATASOURCE, L"ctp2_lx", &rgDBProperties[0]);

	//SetupOption(DBPROP_AUTH_INTEGRATED, L"SSPI", &rgDBProperties[1]);

	SetupOption(DBPROP_INIT_DATASOURCE, L"172.19.124.72", &rgDBProperties[1]);
	//SetupOption(DBPROP_INIT_LOCATION, L"172.19.124.72", &rgDBProperties[2]);
	//密碼
	SetupOption(DBPROP_AUTH_PASSWORD, L"123456", &rgDBProperties[3]);
	//用戶名
	SetupOption(DBPROP_AUTH_USERID, L"sa", &rgDBProperties[4]);

	if (!SUCCEEDED(hr = CreateSessionCommand(rgPropertySets, 1, SQLNCLI_CLSID)))
		goto cleanup;

	time_t begin;
	time(&begin);
	// Get IRowsetFastLoad and insert data into IRFLTable.
	
	if (FAILED(hr = FastInsertData()))
			goto cleanup;

	time_t end;
	time(&end);
	printf("Elapse Time= [%lld]\n", end - begin);

cleanup:
	// Release memory.
	if (rgProperties && rgProperties->rgProperties)
		delete[](rgProperties->rgProperties);
	if (rgProperties)
		delete[]rgProperties;
	if (pIDBCreateCommand)
		pIDBCreateCommand->Release();

	if (pIAccessor)
		pIAccessor->Release();

	if (pIRowset)
		pIRowset->Release();
	if (g_pIMalloc)
		g_pIMalloc->Release();

	if (g_pIDBInitialize) {
		hr2 = g_pIDBInitialize->Uninitialize();
		if (FAILED(hr2))
			printf("Uninitialize failed\n");
	}

	if (fInitialized)
		CoUninitialize();

	if (SUCCEEDED(hr))
		printf("Test completed successfully.\n\n");
	else
		printf("Test failed.\n\n");

	system("pause");
}

void set_bindings()
{
	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]);
	set_bind(g_bindings[1], 2, offsetof(Data, date_len), offsetof(Data, date_status), offsetof(Data, date), col_len[1], col_type[1]);
	set_bind(g_bindings[2], 3, offsetof(Data, time_len), offsetof(Data, time_status), offsetof(Data, time), col_len[2], col_type[2]);
	set_bind(g_bindings[3], 4, offsetof(Data, reff_len), offsetof(Data, reff_status), offsetof(Data, reff), col_len[3], col_type[3]);
	set_bind(g_bindings[4], 5, offsetof(Data, acc_len), offsetof(Data, acc_status), offsetof(Data, acc), col_len[4], col_type[4]);
	set_bind(g_bindings[5], 6, offsetof(Data, stock_len), offsetof(Data, stock_status), offsetof(Data, stock), col_len[5], col_type[5]);
	set_bind(g_bindings[6], 7, offsetof(Data, bs_len), offsetof(Data, bs_status), offsetof(Data, bs), col_len[6], col_type[6]);
	set_bind(g_bindings[7], 8, offsetof(Data, price_len), offsetof(Data, price_status), offsetof(Data, price), col_len[7], col_type[7]);
	set_bind(g_bindings[8], 9, offsetof(Data, qty_len), offsetof(Data, qty_status), offsetof(Data, qty), col_len[8], col_type[8]);
	set_bind(g_bindings[9], 10, offsetof(Data, status_len), offsetof(Data, status_status), offsetof(Data, status), col_len[9], col_type[9]);
	set_bind(g_bindings[10], 11, offsetof(Data, owflag_len), offsetof(Data, owflag_status), offsetof(Data, owflag), col_len[10], col_type[10]);
	set_bind(g_bindings[11], 12, offsetof(Data, ordrec_len), offsetof(Data, ordrec_status), offsetof(Data, ordrec), col_len[11], col_type[11]);
	set_bind(g_bindings[12], 13, offsetof(Data, firmid_len), offsetof(Data, firmid_status), offsetof(Data, firmid), col_len[12], col_type[12]);
	set_bind(g_bindings[13], 14, offsetof(Data, branchid_len), offsetof(Data, branchid_status), offsetof(Data, branchid), col_len[13], col_type[13]);
	set_bind(g_bindings[14], 15, offsetof(Data, checkord_len), offsetof(Data, checkord_status), offsetof(Data, checkord), col_len[14], col_type[14]);
}

void set_bind(DBBINDING &binding, int col, DBBYTEOFFSET len_offset, DBBYTEOFFSET status_offset, DBBYTEOFFSET value_offset, DBLENGTH len, DBTYPE type)
{
	binding.dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
	binding.iOrdinal = col;
	binding.pTypeInfo = NULL;
	binding.obValue = value_offset;
	binding.obLength = len_offset;
	binding.obStatus = status_offset;
	binding.cbMaxLen = len;   // Size of varchar column.
	binding.pTypeInfo = NULL;
	binding.pObject = NULL;
	binding.pBindExt = NULL;
	binding.dwFlags = 0;
	binding.eParamIO = DBPARAMIO_NOTPARAM;
	binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
	binding.bPrecision = 0;
	binding.bScale = 0;
	binding.wType = type;
}




//插入委託表
HRESULT FastInsertData() {
	HRESULT hr = E_FAIL;
	HRESULT hr2 = E_FAIL;
	DBID TableID;

	IDBCreateSession* pIDBCreateSession = NULL;
	IOpenRowset* pIOpenRowsetFL = NULL;
	IRowsetFastLoad* pIFastLoad = NULL;

	IAccessor* pIAccessor = NULL;
	HACCESSOR hAccessor = 0;
	DBBINDSTATUS bindingStatus[15] = { 0 };


	TableID.uName.pwszName = NULL;
	LONG i = 0;
	void* pData = NULL;

	TableID.eKind = DBKIND_NAME;
	// if ( !(TableID.uName.pwszName = new WCHAR[wcslen(g_wszTable) + 2]) )
	LPOLESTR x = TableID.uName.pwszName = new WCHAR[wcslen(g_wszTable) + 2];
	if (!x)
		return E_FAIL;
	wcsncpy_s(TableID.uName.pwszName, wcslen(g_wszTable) + 2, g_wszTable, wcslen(g_wszTable) + 1);
	TableID.uName.pwszName[wcslen(g_wszTable) + 1] = (WCHAR)NULL;

	// Get the fastload pointer.
	if (FAILED(hr = SetFastLoadProperty(TRUE)))
		goto cleanup;

	if (FAILED(hr =
		g_pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void **)&pIDBCreateSession)))
		goto cleanup;

	if (FAILED(hr =
		pIDBCreateSession->CreateSession(NULL, IID_IOpenRowset, (IUnknown **)&pIOpenRowsetFL)))
		goto cleanup;

	// Get IRowsetFastLoad initialized to use the test table.
	if (FAILED(hr =
		pIOpenRowsetFL->OpenRowset(NULL,
		&TableID,
		NULL,
		IID_IRowsetFastLoad,
		0,
		NULL,
		(LPUNKNOWN *)&pIFastLoad)))
		goto cleanup;

	set_bindings();

	if (FAILED(hr =
		pIFastLoad->QueryInterface(IID_IAccessor, (void **)&pIAccessor)))
		return hr;

	if (FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
		15,
		g_bindings,
		ROUND_UP(sizeof(Data), COLUMN_ALIGNVAL),
		&hAccessor,
		bindingStatus)))
		return hr;

	Data *datas = new Data[COUNT];
	for (int i = 0; i < COUNT; i++)
	{
		datas[i].rec_num_len = col_len[0];
		datas[i].date_len = col_len[1];
		datas[i].time_len = col_len[2];
		datas[i].reff_len = col_len[3];
		datas[i].acc_len = col_len[4];
		datas[i].stock_len = col_len[5];
		datas[i].bs_len = col_len[6];
		datas[i].price_len = col_len[7];
		datas[i].qty_len = col_len[8];
		datas[i].status_len = col_len[9];
		datas[i].owflag_len = col_len[10];
		datas[i].ordrec_len = col_len[11];
		datas[i].firmid_len = col_len[12];
		datas[i].branchid_len = col_len[13];
		datas[i].checkord_len = col_len[14];

		datas[i].rec_num_status = 0;
		datas[i].date_status = 0;
		datas[i].time_status = 0;
		datas[i].reff_status = 0;
		datas[i].acc_status = 0;
		datas[i].stock_status = 0;
		datas[i].bs_status = 0;
		datas[i].price_status = 0;
		datas[i].qty_status = 0;
		datas[i].status_status = 0;
		datas[i].owflag_status = 0;
		datas[i].ordrec_status = 0;
		datas[i].firmid_status = 0;
		datas[i].branchid_status = 0;
		datas[i].checkord_status = 0;
	}

	for (int i = 0; i < COUNT; i++)
	{
			datas[i].rec_num = rec_num++;
			strncpy(datas[i].date, "20150120", col_len[1]);
			strncpy(datas[i].time, "13:20:10", col_len[2]);
			strncpy(datas[i].reff, "1234567890", col_len[3]);
			strncpy(datas[i].acc, "0000011111", col_len[4]);
			strncpy(datas[i].stock, "123456", col_len[5]);
			strncpy(datas[i].bs, "B", col_len[6]);
			strncpy(datas[i].price, "1.000", col_len[7]);
			strncpy(datas[i].qty, "1000", col_len[8]);
			strncpy(datas[i].status, "R", col_len[9]);
			strncpy(datas[i].owflag, "ORD", col_len[10]);
			strncpy(datas[i].ordrec, "1", col_len[11]);
			strncpy(datas[i].firmid, "123", col_len[12]);
			strncpy(datas[i].branchid, "20201", col_len[13]);
			memset(datas[i].checkord, 0, col_len[14]);

			if (FAILED(hr = pIFastLoad->InsertRow(hAccessor, &datas[i])))
			{

				DumpErrorInfo(pIFastLoad, IID_ISQLServerErrorInfo);

				goto cleanup;
			}

		if (FAILED(hr = pIFastLoad->Commit(TRUE)))
		{
			DumpErrorInfo(pIFastLoad, IID_ISQLServerErrorInfo);

			printf("Error on IRFL::Commit\n");
		}
	}
cleanup:
	if (FAILED(hr2 = SetFastLoadProperty(FALSE)))
		printf("SetFastLoadProperty(FALSE) failed with %x", hr2);

	if (pIAccessor && hAccessor)
	if (FAILED(pIAccessor->ReleaseAccessor(hAccessor, NULL)))
		hr = E_FAIL;

	if (pIAccessor)
		pIAccessor->Release();

	if (pIFastLoad)
		pIFastLoad->Release();

	if (pIOpenRowsetFL)
		pIOpenRowsetFL->Release();

	if (pIDBCreateSession)
		pIDBCreateSession->Release();

	if (TableID.uName.pwszName)
		delete[]TableID.uName.pwszName;

	delete[] datas;

	return hr;
}

HRESULT SetFastLoadProperty(BOOL fSet) {
	HRESULT hr = S_OK;
	IDBProperties* pIDBProps = NULL;
	DBPROP rgProps[1];
	DBPROPSET PropSet;

	VariantInit(&rgProps[0].vValue);

	rgProps[0].dwOptions = DBPROPOPTIONS_REQUIRED;
	rgProps[0].colid = DB_NULLID;
	rgProps[0].vValue.vt = VT_BOOL;
	rgProps[0].dwPropertyID = SSPROP_ENABLEFASTLOAD;

	if (fSet == TRUE)
		rgProps[0].vValue.boolVal = VARIANT_TRUE;
	else
		rgProps[0].vValue.boolVal = VARIANT_FALSE;

	PropSet.rgProperties = rgProps;
	PropSet.cProperties = 1;
	PropSet.guidPropertySet = DBPROPSET_SQLSERVERDATASOURCE;

	if (SUCCEEDED(hr = g_pIDBInitialize->QueryInterface(IID_IDBProperties, (LPVOID *)&pIDBProps)))
		hr = pIDBProps->SetProperties(1, &PropSet);

	VariantClear(&rgProps[0].vValue);

	if (pIDBProps)
		pIDBProps->Release();

	return hr;
}

HRESULT CreateSessionCommand(DBPROPSET* rgPropertySets,// @parm [in] property sets
	ULONG ulcPropCount,   // @parm [in] count of prop sets.
	CLSID clsidProv) {  // @parm [in] Provider CLSID.

	HRESULT hr = NOERROR;
	IDBCreateSession* pIDBCreateSession = NULL;
	IDBProperties* pIDBProperties = NULL;
	UWORD i = 0, j = 0;   // indexes.

	if (ulcPropCount && !rgPropertySets) {
		hr = E_INVALIDARG;
		return hr;
	}

	if (!SUCCEEDED(hr = CoCreateInstance(clsidProv,
		NULL, CLSCTX_INPROC_SERVER,
		IID_IDBInitialize,
		(void **)&g_pIDBInitialize)))
		goto CLEANUP;

	if (!SUCCEEDED(hr = g_pIDBInitialize->QueryInterface(IID_IDBProperties,
		(void **)&pIDBProperties)))
		goto CLEANUP;

	if (!SUCCEEDED(hr = pIDBProperties->SetProperties(ulcPropCount, rgPropertySets)))
		goto CLEANUP;

	if (!SUCCEEDED(hr = g_pIDBInitialize->Initialize())) {

		printf("Call to initialize failed.\n");
		goto CLEANUP;
	}

CLEANUP:
	if (pIDBProperties)
		pIDBProperties->Release();
	if (pIDBCreateSession)
		pIDBCreateSession->Release();

	for (i = 0; i < ulcPropCount; i++)
	for (j = 0; j < rgPropertySets[i].cProperties; j++)
		VariantClear(&(rgPropertySets[i].rgProperties[j]).vValue);
	return hr;
}

void SetupOption(DBPROPID PropID, WCHAR *wszVal, DBPROP * pDBProp) {
	pDBProp->dwPropertyID = PropID;
	pDBProp->dwOptions = DBPROPOPTIONS_REQUIRED;
	pDBProp->colid = DB_NULLID;
	pDBProp->vValue.vt = VT_BSTR;
	pDBProp->vValue.bstrVal = SysAllocStringLen(wszVal, wcslen(wszVal));
}

// DumpErrorInfo queries SQLOLEDB error interfaces, retrieving available
// status or error information.
void DumpErrorInfo
(
IUnknown* pObjectWithError,
REFIID IID_InterfaceWithError
)
{

	// Interfaces used in the example.
	IErrorInfo*             pIErrorInfoAll = NULL;
	IErrorInfo*             pIErrorInfoRecord = NULL;
	IErrorRecords*          pIErrorRecords = NULL;
	ISupportErrorInfo*      pISupportErrorInfo = NULL;
	ISQLErrorInfo*          pISQLErrorInfo = NULL;
	ISQLServerErrorInfo*    pISQLServerErrorInfo = NULL;

	// Number of error records.
	ULONG                   nRecs;
	ULONG                   nRec;

	// Basic error information from GetBasicErrorInfo.
	ERRORINFO               errorinfo;

	// IErrorInfo values.
	BSTR                    bstrDescription;
	BSTR                    bstrSource;

	// ISQLErrorInfo parameters.
	BSTR                    bstrSQLSTATE;
	LONG                    lNativeError;

	// ISQLServerErrorInfo parameter pointers.
	SSERRORINFO*            pSSErrorInfo = NULL;
	OLECHAR*                pSSErrorStrings = NULL;

	// Hard-code an American English locale for the example.
	DWORD                   MYLOCALEID = 0x0409;

	// Only ask for error information if the interface supports
	// it.
	if (FAILED(pObjectWithError->QueryInterface(IID_ISupportErrorInfo,
		(void**)&pISupportErrorInfo)))
	{
		wprintf_s(L"SupportErrorErrorInfo interface not supported");
		return;
	}
	if (FAILED(pISupportErrorInfo->
		InterfaceSupportsErrorInfo(IID_InterfaceWithError)))
	{
		wprintf_s(L"InterfaceWithError interface not supported");
		return;
	}

	// Do not test the return of GetErrorInfo. It can succeed and return
	// a NULL pointer in pIErrorInfoAll. Simply test the pointer.
	GetErrorInfo(0, &pIErrorInfoAll);

	if (pIErrorInfoAll != NULL)
	{
		// Test to see if it's a valid OLE DB IErrorInfo interface 
		// exposing a list of records.
		if (SUCCEEDED(pIErrorInfoAll->QueryInterface(IID_IErrorRecords,
			(void**)&pIErrorRecords)))
		{
			pIErrorRecords->GetRecordCount(&nRecs);

			// Within each record, retrieve information from each
			// of the defined interfaces.
			for (nRec = 0; nRec < nRecs; nRec++)
			{
				// From IErrorRecords, get the HRESULT and a reference
				// to the ISQLErrorInfo interface.
				pIErrorRecords->GetBasicErrorInfo(nRec, &errorinfo);
				pIErrorRecords->GetCustomErrorObject(nRec,
					IID_ISQLErrorInfo, (IUnknown**)&pISQLErrorInfo);

				// Display the HRESULT, then use the ISQLErrorInfo.
				wprintf_s(L"HRESULT:\t%#X\n", errorinfo.hrError);

				if (pISQLErrorInfo != NULL)
				{
					pISQLErrorInfo->GetSQLInfo(&bstrSQLSTATE,
						&lNativeError);

					// Display the SQLSTATE and native error values.
					wprintf_s(L"SQLSTATE:\t%s\nNative Error:\t%ld\n",
						bstrSQLSTATE, lNativeError);

					// SysFree BSTR references.
					SysFreeString(bstrSQLSTATE);

					// Get the ISQLServerErrorInfo interface from
					// ISQLErrorInfo before releasing the reference.
					pISQLErrorInfo->QueryInterface(
						IID_ISQLServerErrorInfo,
						(void**)&pISQLServerErrorInfo);

					pISQLErrorInfo->Release();
				}

				// Test to ensure the reference is valid, then
				// get error information from ISQLServerErrorInfo.
				if (pISQLServerErrorInfo != NULL)
				{
					pISQLServerErrorInfo->GetErrorInfo(&pSSErrorInfo,
						&pSSErrorStrings);

					// ISQLServerErrorInfo::GetErrorInfo succeeds
					// even when it has nothing to return. Test the
					// pointers before using.
					if (pSSErrorInfo)
					{
						// Display the state and severity from the
						// returned information. The error message comes
						// from IErrorInfo::GetDescription.
						wprintf_s(L"Error state:\t%d\nSeverity:\t%d\n",
							pSSErrorInfo->bState,
							pSSErrorInfo->bClass);

						// IMalloc::Free needed to release references
						// on returned values. For the example, assume
						// the g_pIMalloc pointer is valid.
						g_pIMalloc->Free(pSSErrorStrings);
						g_pIMalloc->Free(pSSErrorInfo);
					}

					pISQLServerErrorInfo->Release();
				}

				if (SUCCEEDED(pIErrorRecords->GetErrorInfo(nRec,
					MYLOCALEID, &pIErrorInfoRecord)))
				{
					// Get the source and description (error message)
					// from the record's IErrorInfo.
					pIErrorInfoRecord->GetSource(&bstrSource);
					pIErrorInfoRecord->GetDescription(&bstrDescription);

					if (bstrSource != NULL)
					{
						wprintf_s(L"Source:\t\t%s\n", bstrSource);
						SysFreeString(bstrSource);
					}
					if (bstrDescription != NULL)
					{
						wprintf_s(L"Error message:\t%s\n",
							bstrDescription);
						SysFreeString(bstrDescription);
					}

					pIErrorInfoRecord->Release();
				}
			}

			pIErrorRecords->Release();
		}
		else
		{
			// IErrorInfo is valid; get the source and
			// description to see what it is.
			pIErrorInfoAll->GetSource(&bstrSource);
			pIErrorInfoAll->GetDescription(&bstrDescription);

			if (bstrSource != NULL)
			{
				wprintf_s(L"Source:\t\t%s\n", bstrSource);
				SysFreeString(bstrSource);
			}
			if (bstrDescription != NULL)
			{
				wprintf_s(L"Error message:\t%s\n", bstrDescription);
				SysFreeString(bstrDescription);
			}
		}

		pIErrorInfoAll->Release();
	}
	else
	{
		wprintf_s(L"GetErrorInfo failed.");
	}

	pISupportErrorInfo->Release();

	return;
}

使用上面方法,每秒鐘可以插入3萬多條記錄。
OLEDB的接口確實有點繁瑣~有時候讀了好多遍MSDN上的接口說明,也執行不正確。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章