C#中的可滚动ODBC游标

时间:2012-12-31 21:04:24

标签: c# .net sql-server cursor

我是C ++程序员,我不熟悉.NET数据库模型。我通常使用IDataReaderOdbcDataReaderOledbDataReaderSqlDataReader)来读取数据库中的数据。有时当我需要大量数据时,我使用DataAdapter,但是我应该怎么做才能实现存在于ODBC等本机库中的可滚动游标的功能?

<小时/> 谢谢大家的回答,但我处于一种我无法接受的情况,当然这是我的错,并没有完全解释我的问题。我将其解释为现在删除的一个答案中的评论。

我必须编写一个程序,作为客户端程序和MSSQL之间的代理,对于这个库,我有以下要求:

  • 我的程序应该与MSSQL2000兼容
  • 我不知道用户将发送的所有表和查询,我应该只是添加一些信息,创建一个日志,然后对MSSQL执行它,所以真的很难使用基于查询的有序字段或表的主键的技术(我的所有作品都在一个数据库中,但该数据库很大并且可能会随着时间而变化)。
  • 客户端只需要一部分数据,大多数DBMS支持LIMIT OFFSET,遗憾的是MSSQL不支持它,ROW_NUMBER中不存在MSSQL2000如果它支持,那么我再次需要了解程序逻辑,并且需要解析SQL命令(实际上我用boost::spirit编写了一个解析库,但这是本机代码,除此之外我还不是100%肯定它的功能)。
  • 我可能有多个客户端,但是大多数将由他们发送的查询是少数预定义查询之一(当然用户仍然发送自定义查询但其约占所有查询的30%),所以我想我可以打开一些可滚动游标,并使用该游标和自定义缓存响应客户端。
  • 服务器机器及其MSSQL将专用于我的程序,所以我真的想利用服务器和DBMS的所有功能来实现我的功能。

现在:

  • 使用可滚动游标有什么问题以及为什么要避免使用它们?
  • 如何在.NET中使用可滚动游标?

4 个答案:

答案 0 :(得分:3)

在SQL Server中,您可以创建分页的查询。您可以从应用程序轻松处理的页码。您无需为此任务创建游标。

对于SQL Server 2005更高

SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY ID) AS ROW FROM TABLEA ) AS ALIAS 
WHERE ROW > 40 
AND ROW <= 49

对于SQL Server 2000

SELECT TOP 10 T.* FROM TABLA AS T WHERE T.ID NOT IN
    ( SELECT TOP 39 id from tabla order by id desc )
ORDER BY T.ID DESC

PD:已编辑为包含对SQL Server 2000的支持

答案 1 :(得分:2)

我通常使用DataReader.Read()来跳过在不支持分页的数据库上进行分页时我不想使用的所有行。

如果您不想自己构建SQL分页查询,可以自由使用我的分页类:https://github.com/jgauffin/Griffin.Data/blob/master/src/Griffin.Data/BasicLayer/Paging/SqlServerPager.cs

答案 2 :(得分:2)

当Microsoft设计ADO.NET API时,他们决定只公开firehose游标(IDataReader等)。这可能会或可能不会对您造成问题。你说你想要“可滚动游标的功能”,但这可能意味着各种各样的事情,而不仅仅是分页,每个特定的用例都可以通过各种方式解决。例如:

要求:用户应该可以随意向上和向下翻页结果。

  • 一次仅检索一页数据,例如使用ROW_NUMBER()函数。这比滚动光标更有效。

要求:我有一个非常大的数据集,我只想一次处理一行,以避免内存不足。

  • 使用ADO.NET提供的firehose游标。请注意,只有在(a)您在循环期间根本不需要访问数据库,或(b)您在连接字符串中配置了MARS时,这才是实用的。
  • 通过将一组唯一标识符检索到数组中来模拟键集游标,然后循环遍历数组并一次读取一行数据。

要求:我正在进行一项复杂的计算,涉及在结果集中向前和向后移动。

  • 您应该能够重新编写算法以消除此要求。例如,读取一组行,处理它们,读取另一组行,处理它们等等。

更新(问题中提供了更多信息)

您的业务要求太多了。您必须处理假定存在可滚动游标的任意查询,但您不能提供可滚动游标,并且您不能重写客户端代码以不使用可滚动游标。这是一个不可能的位置。我建议你坚持你现在拥有的东西(C ++和ODBC),不要试图在.NET中重写它。

答案 3 :(得分:2)

我不认为游标会为你的特定情况而工作。主要原因是你有3层。但是,让我们退两步。

大多数3层应用程序都有无状态中间层(您的c ++代码)。缓存很好,因为它实际上只是一个优化,并没有在中间层创建任何真实状态。中间层通常具有少量到数据库的打开会话。因为打开db会话对于处理器而言是昂贵的,并且在db会话打开之后,在数据库服务器上保留一定量的RAM。当中间层收到请求时,将处理该请求并将其传递给SQL数据库。可以使用算法来挑选任何打开的会话,或者甚至可以随机地完成。在此模型中,无法知道哪个会话将接收下一个请求。游标属于收到原始查询请求的会话。所以你真的不希望接收会话是那个打开游标的会话。

我描述的3层模型主要用于Web应用程序,因此可以扩展到数百或数千个客户端。如果SQL服务器永远无法打开那么多会话。 Microsoft ADO.NET已经有许多功能来支持我所描述的架构,因此实现起来并不是很难。根据具体情况,即使在非Web应用程序中也是如此。您可以跟踪您的会话,以便您可以为每个客户端打开一个会话,我首先要确保用例证明这一点。知道开放游标也可以占用大量资源。

游标仍然在单个事务中占有一席之地,只是很难让它们保持打开状态,以便客户端应用程序可以获取/更新结果集中的值。

我建议您在查询事务中执行以下操作。在单独的表中存储查询中主表的主键值。在单独的表上包括其他值,如sessionid和rownumber。通过链接到原始查询中的新表返回一些第一行。在后续调用中,只需链接到新表即可再次查询相应的行。您将需要等效的缓存机制来清除旧数据,并根据您的需要刷新结果集。