簡體   English   中英

來自ODBC的SQL語句比T-SQL慢得多

[英]SQL statement much slower from ODBC than in T-SQL

我有一個C / C ++ DLL,它連接到SQL,並在一個循環中快速發出大量ODBC查詢。 唯一的問題是,從ODBC DLL中發現它比在Management Studio中從T-SQL運行查詢要慢得多。 速度降低了多個數量級。

起初我以為它可能是查詢本身,但是后來我將其簡化為一個簡單的“選擇NULL”,仍然得到了相同的結果。

我想知道這是預期的還是我缺少或出錯的某些ODBC設置?

首先,我這樣連接(為簡便起見,我省略了所有錯誤檢查,但是,retcode在所有情況下都返回SQL_SUCCESS):

char *connString = "Driver={SQL Server};Server=.\\ENT2012;uid=myuser;pwd=mypwd";
...
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, SQL_IS_UINTEGER);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (void*)5, 0);
retcode = SQLDriverConnect(
    hdbc, 
    0,
    (SQLTCHAR*) connString,
    SQL_NTS, 
    connStringOut,
    MAX_PATH, 
    (SQLSMALLINT*)&connLen, 
    SQL_DRIVER_COMPLETE);

然后,我准備該語句,綁定一個參數(在此示例中未使用),並綁定這樣的列:

char queryString = "select NULL;";
SQLLEN g_int32 = 4;
SQLLEN bytesRead = 0;
...
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt)
retcode = SQLPrepare(hstmt, queryString, SQL_NTS);
retcode = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, 
    SQL_C_LONG, SQL_INTEGER, sizeof(int), 0, spid, 0, (SQLLEN*)&g_int32))
retcode = SQLBindCol(hstmt, 1, SQL_C_CHAR, col_1, 32, &bytesRead);

最后,我在這樣的循環中重復調用查詢(例如10000次):

retcode = SQLExecute(hstmt);
retcode = SQLFetch(hstmt);
SQLCloseCursor(hstmt);

在ODBC DLL中運行10000次大約需要90秒。 在運行SQL 2012 x64的4核Windows 2008 R2 Server上進行測試。

另一方面,如果運行,在我看來是Management Studio中的等效測試,則只需不到一秒鍾的時間:

declare @sql varchar(128), @repeat int;
set @repeat = 10000;
set @sql = 'select NULL;';
while @repeat > 0 begin
    exec(@sql);
    set @repeat = @repeat - 1;
end;

有人可以指出我忽略的內容嗎? 我的邏輯有缺陷嗎?

謝謝。

尼爾·韋徹

www.netlib.com

這個評論太長了

declare @sql varchar(128), @repeat int;
set @repeat = 10000;
set @sql = 'select NULL;';
while @repeat > 0 begin
    exec(@sql);
    set @repeat = @repeat - 1;
end;

不能真實模擬與10000個遠程呼叫相同的模擬。 exec繞開了建立請求的許多內部步驟。 要模擬10000個呼叫,請在SSMS中執行以下操作:

select NULL;
go 10000

和測量。 可能應使用文本輸出,以避免在SSMS網格顯示周圍出現計時。

我對T-SQL的知識不是很熟悉,但是這里有幾點需要考慮。

您的ODBC驅動程序必須通過您的網絡傳輸數據,我懷疑T-SQL執行不會。 在磁盤IO旁邊,在網絡上傳輸數據是ODBC驅動程序必須做的最慢的事情之一。 您可能會發現,驅動程序正在花費大量時間,要么等待數據傳輸,要么清除數據。

另外,對我來說還不清楚您的T-SQL示例實際上是在移動和傳輸數據,但是在調用SQLFetch時,您的ODBC示例確實在移動。 T-SQL可能只是在執行查詢而從未獲取任何數據。 因此,從循環中刪除SQLFetch可能是一個更加平等的比較。

要查看數據傳輸是否是您的限制因素,請估算使用ODBC提取的所有記錄中將包含多少數據,並嘗試使用FTP之類的方法在兩台計算機之間移動那么多數據。 ODBC驅動程序永遠無法比簡單的原始數據傳輸更快地獲取數據。 我看到您只是在獲取NULL,因此結果集中的內容並不多,但驅動程序和數據庫仍在它們之間傳輸數據來滿足此請求。 每次執行\\提取可能是數百個字節。

我遇到了同樣的問題。 我通過將ODBC驅動程序的DSN的“游標默認模式”設置(通過ODBC管理器工具)從“ READ_ONLY”更改為“ READ_ONLY_STREAMING”來解決了。 僅此一項就使我的應用程序(查詢數據並將它們寫入文件)的速度從使用Java 32位的260秒提高到了51秒,而使用C ++的速度從1234秒提高到了11秒。 看到這篇文章: http : //www.etl-tools.com/forum/visual-importer/1587-question-about-data-transformation-memory-usage?start=6

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM