加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MsSql教程 > 正文

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

发布时间:2020-12-12 07:26:11 所属栏目:MsSql教程 来源:网络整理
导读:我们有一个应用程序在MFC(VS2010)中通过C Database / CRecordset使用ODBC. 我们实施了两个后端. MSSQL和 MySQL. 现在,当我们使用MSSQL(使用Native Client 10.0)时,使用SELECT检索记录通过慢速链接(例如VPN)非常慢. MySQL ODBC驱动程序没有表现出这种令人讨厌
我们有一个应用程序在MFC(VS2010)中通过C Database / 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 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.

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读