SQL Native Client 10性能不佳(由于服务器端游标)

我们有一个应用程序在MFC(VS2010)中通过C Database / CRecordset使用ODBC.
我们实施了两个后端. MSsqlMySQL.

现在,当我们使用MSsql(使用Native Client 10.0)时,使用SELECT检索记录通过慢速链接(例如VPN)非常慢. MysqL ODBC驱动程序没有表现出这种令人讨厌的行为.

例如:

CRecordset r(&m_db);
r.Open(CRecordset::snapshot,L"SELECT a.something,b.sthelse FROM TableA AS a LEFT JOIN TableB AS b ON a.ID=b.Ref");
r.MoveFirst();
while(!r.ISEOF())
{
    // Retrieve
    CString strData;
    crs.GetFieldValue(L"a.something",strData);
    crs.MoveNext();
}

现在,使用MysqL驱动程序,一切都按预期运行.返回查询,一切都闪电般快.
但是,使用MSsql Native Client,事情会变慢,因为在每个MoveNext()上,驱动程序都与服务器通信.

我认为这是由于服务器端游标,但我没有找到一种方法来禁用它们.我试过用过:

::sqlSetConnectAttr(m_db.m_hdbc,sql_ATTR_ODBC_CURSORS,sql_CUR_USE_ODBC,sql_IS_INTEGER);

但这也没有帮助. sql Profiler中的sp_cursorfetch()等仍有长期运行的exec.
我还尝试了一个带有sqlAPI和批量提取的小型参考项目,但是它在FetchNext()中也会挂起很长时间(即使结果集中只有一条记录).
但这仅适用于具有LEFT JOINS,表值函数等的查询.
请注意,查询不会花费那么长时间 – 通过sql Studio在相同的连接上执行相同的sql会在合理的时间内返回.

问题1:是否有可能以某种方式让本机客户端“缓存”所有结果本地使用本地游标的方式与MysqL驱动程序似乎一样?

也许这是完全错误方法,但我不确定如何做到这一点.

我们想要的只是从SELECT中一次检索所有数据,然后再不谈论服务器直到下一个查询.
我们不关心记录集更新,删除等或任何废话.我们只想检索数据.
我们采用该记录集,获取所有数据并删除它.

问题2:有没有更有效的方法来使用ODBC在MFC中检索数据?

解决方法

我对这个问题进行了修改,发现了这两个链接

MSDN Link

MSDN Blog

在第一个链接中,它描述了仅当更改认选项时,Native Client 10才使用服务器端游标:

When these options are set to their defaults at the time an sql statement is executed,the sql Server Native Client ODBC driver does not use a server cursor to implement the result set; instead,it uses a default result set.

Link 2是一个博客,它是一个sql Dev博客,它说:

It turned out that the developer did not explicitly ask for a server cursor. But when he did block fetches,as a side effect,the sql Server ODBC driver asked for a server cursor…that is unexpected!

是的,当然这是出乎意料的……

How can I do block fetches over a Default Result Set (fire hose cursor) instead of a server cursor?

现在,解决方案的实施是这样的:

代替:

// crs is a CRecordSet
crs.Open(CRecordset::snapshot,L"SELECT something...");

做这个:

// crs is a CRecordSet
crs.Open(CRecordset::forwardOnly,L"SELECT something...");

这个简单的更改不会触发创建服务器端游标,并模仿MysqL驱动程序的行为.

缺点是现在您无法通过(Microsoft推荐)方式检索行计数:

while(crs.MoveNext()) nCount++;

无论如何,这是一个坏主意.此外,:: sqlGetRowCount()将不再一直有效.

我已经解决了这个问题(这应该适用于任何ANSI兼容的sql源):

//strQuery is the random query passed to CountRows()
std::wstringstream ssQuery;
ssQuery << L"SELECT COUNT(*) AS Count FROM (" << strQuery << L") AS t";
CRecordset crs(&m_Database);
crs.Open(CRecordset::forwardOnly,ssQuery.str().c_str());
// Now retrieve the only "Count" field from the recordset.

我希望将来可以帮助别人.

相关文章

SELECT a.*,b.dp_name,c.pa_name,fm_name=(CASE WHEN a.fm_n...
if not exists(select name from syscolumns where name=&am...
select a.*,pano=a.pa_no,b.pa_name,f.dp_name,e.fw_state_n...
要在 SQL Server 2019 中设置定时自动重启,可以使用 Window...
您收到的错误消息表明数据库 &#39;EastRiver&#39; 的...
首先我需要查询出需要使用SQL Server Profiler跟踪的数据库标...