我们有一个在MFC(VS2010)中通过CDatabase / CRecordset使用ODBC的应用程序。 我们实施了两个后端。 MSSQL和MySQL。
现在,当我们使用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事件探查器中,sp_cursorfetch()等仍有长期运行的exec。 我还尝试了一个带有SQLAPI和批量提取的小型参考项目,但是在FetchNext()中也会挂起很长时间(即使结果集中只有一条记录)。 但这仅适用于具有LEFT JOINS,表值函数等的查询。 请注意,查询不需要那么长时间 - 通过SQL Studio在相同的连接上执行相同的SQL,并在合理的时间内返回。
问题1:是否有可能以某种方式让本机客户端“缓存”本地所有结果以类似MySQL驱动程序的方式使用本地游标?
也许这完全是错误的做法,但我不确定如何做到这一点。
我们想要的只是从SELECT中一次检索所有数据,然后再不谈论服务器直到下一个查询。 我们不关心记录集更新,删除等或任何废话。我们只想检索数据。 我们接受该记录集,获取所有数据并删除它。
问题2:是否有更有效的方法可以使用ODBC在MFC中检索数据?
答案 0 :(得分:3)
我已经对这个问题进行了修改,发现了这两个链接:
在第一个链接中,它描述了仅当更改默认选项时,Native Client 10才使用服务器端游标:
在执行SQL语句时将这些选项设置为其默认值时,SQL Server Native Client ODBC驱动程序不使用服务器游标来实现结果集。相反,它使用默认结果集。
Link 2是一个博客,它是一个SQL Dev博客,它说:
事实证明,开发人员没有明确要求服务器游标。但当他确实阻止抓取时,作为副作用,SQL Server ODBC驱动程序要求服务器游标......这是意外的!
是的,当然这是出乎意料的......
如何通过默认结果集(消防管光标)而不是服务器光标进行块提取?
现在,解决方案的实施是这样的:
而不是:
// 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.
我希望将来可以帮助别人。