C#中IDataReader和DataSet的区别是啥呢?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#中IDataReader和DataSet的区别是啥呢?相关的知识,希望对你有一定的参考价值。

C#中IDataReader和DataSet有什么区别
具体怎么使用啊?

参考技术A 用connection对象和command对象与数据库连接并交互后,有两种方法来访问获取的结果。
1.使用DataReader对象,用来逐行从数据源获取数据并处理;
2.使用DataSet对象,用来将数据存到内存中进行处理。
参考技术B DataReader是读记录,
DataSet是临时存放数据库
参考技术C ADO.NET提供以下两个对象,用于检索关系数据并将其存储在内存中:DataSet和DataReader。DataSet提供一个内存中数据的关系表示形式,一整套包括一些表在内的数据(这些表包含数据、对数据进行排序并约束数据),以及表之间的关系。DataReader提供一个来自数据库的快速、仅向前、只读数据流。
当使用DataSet时,经常会利用DataAdapter(也可能是CommandBuilder)与数据源进行交互。当使用DataSet时,也可以利用DataView对DataSet中的数据应用排序和筛选。也可以从DataSet继承,创建强类型DataSet,用于将表、行和列作为强类型对象属性公开。
当设计应用程序时,要考虑应用程序所需功能的等级,以确定使用DataSet或者是DataReader。
要通过应用程序执行以下操作,就要使用DataSet:
r 在结果的多个离散表之间进行导航。
r 操作来自多个数据源(例如,来自多个数据库、一个XML文件和一个电子表格的混合数据)的数据。
r 在各层之间交换数据或使用XML Web服务。与DataReader不同的是,DataSet能传递给远程客户端。
r 重用同样的记录集合,以便通过缓存获得性能改善(例如排序、搜索或筛选数据)。
r 每条记录都需要执行大量处理。对使用DataReader返回的每一行进行扩展处理会延长服务于DataReader的连接的必要时间,这影响了性能。
r 使用XML操作对数据进行操作,例如可扩展样式表语言转换(XSLT转换)或XPath查询。

对于下列情况,要在应用程序中使用DataReader:
r 不需要缓存数据。
r 要处理的结果集太大,内存中放不下。
r 一旦需要以仅向前、只读方式快速访问数据。
注填充DataSet时,DataAdapter使用DataReader。因此,使用DataAdapter取代DataSet提升的性能表现为节省了DataSet占用内存和填充DataSet需要的循环。一般来说,此性能提升只是象征性的,因此,设计决策应以所需功能为基础。

参考资料:http://hi.baidu.com/huangping0524/blog/item/04a5394f8a68d233aec3ab04.html

本回答被提问者采纳

引发了“System.OutOfMemoryException”类型的异常。 C# 使用 IDataReader 时

【中文标题】引发了“System.OutOfMemoryException”类型的异常。 C# 使用 IDataReader 时【英文标题】:Exception of type 'System.OutOfMemoryException' was thrown. C# when using IDataReader 【发布时间】:2012-12-10 20:03:50 【问题描述】:

我有一个应用程序,我必须从数据库中获取大量数据。 由于它未能获取所有这些行(接近 2,000,000 行...),我将其中断,并且每次运行 sql 查询时,每次仅获取 200,000 行。

我使用向其中输入所有数据的 DataTable(意思是 - 所有 2,000,000 行都应该在那里)。

前几次运行都很好。然后它会因 OutOfMemoryException 而失败。

我的代码如下:

private static void RunQueryAndAddToDT(string sql, string lastRowID, SqlConnection conn, DataTable dt, int prevRowCount)
    
        if (string.IsNullOrEmpty(sql))
        
            sql = generateSqlQuery(lastRowID);
        

        if (conn.State == ConnectionState.Closed)
        
            conn.Open();
        

        using (IDbCommand cmd2 = conn.CreateCommand())
        
            cmd2.CommandType = CommandType.Text;
            cmd2.CommandText = sql;
            cmd2.CommandTimeout = 0;

            using (IDataReader reader = cmd2.ExecuteReader())
            
                while (reader.Read())
                
                    DataRow row = dt.NewRow();
                    row["RowID"] = reader["RowID"].ToString();
                    row["MyCol"] = reader["MyCol"].ToString();
                    ... //In one of these rows it returns the exception.

                    dt.Rows.Add(row);
                
            
        

        if (conn != null)
        
            conn.Close();
        

        if (dt.Rows.Count > prevRowCount)
        
            lastRowID = dt.Rows[dt.Rows.Count - 1]["RowID"].ToString();
            sql = string.Empty;
            RunQueryAndAddToDT(sql, lastRowID, conn, dt, dt.Rows.Count);
        
    

在我看来,读者好像一直在收集行,这就是它只在第三轮或第二轮抛出异常的原因。

不应该像使用那样清理内存吗? 什么可以解决我的问题?

注意:我应该解释一下 - 我别无选择,只能将所有这些行放到数据表中,因为我稍后会对它们进行一些操作,并且行的顺序很重要,我不能拆分它是因为有时我必须将某些行的数据设置为一行等等,所以我不能放弃它。

谢谢。

【问题讨论】:

只是一个注释,如果数据大小增加一倍或三倍怎么办。必须有一个方法才能只拉回一些数据,否则你以后可能会遇到很多麻烦。 加载 2M 行是非常少见的——大多数时候的想法是尽量减少加载的数据量。如果你需要 2M 行,DataTable 可能不是最好的模型(DataTable 有开销)。我个人会将其加载到 POCO 模型中。 【参考方案1】:

既然您使用的是DataTable,让我分享一个我在使用DataTable 时遇到的随机问题。检查您的构建属性。我遇到了 DataTable 随机抛出内存不足异常的问题。事实证明,该项目的构建平台目标设置为Prefer 32-bit。一旦我取消选择该选项,随机内存不足异常就消失了。

【讨论】:

【参考方案2】:

检查您构建的是 64 位进程,而不是 32 位进程,这是 Visual Studio 的默认编译模式。为此,请右键单击您的项目,属性 -> 构建 -> 平台目标:x64。与任何 32 位进程一样,以 32 位编译的 Visual Studio 应用程序的虚拟内存限制为 2GB。

64 位进程没有此限制,因为它们使用 64 位指针,因此它们的理论最大地址空间为 16 艾字节 (2^64)。实际上,Windows x64 将进程的虚拟内存限制为 8TB。那么内存限制问题的解决方案就是编译成64位。

但是,默认情况下,Visual Studio 中对象的大小仍限制为 2GB。您将能够创建多个组合大小大于 2GB 的数组,但默认情况下您不能创建大于 2GB 的数组。希望如果您仍想创建大于 2GB 的数组,可以通过将以下代码添加到 app.config 文件来实现:

<configuration>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" />
  </runtime>
</configuration>

【讨论】:

为我工作!谢谢! 谢谢。为我工作 我正在使用 32 位应用程序,我正在尝试将 1700000 条记录从 sql 阅读器添加到数据表中,它引发了内存不足异常。再次使用上述解决方案后,它抛出了同样的错误。请建议我解决他的问题。【参考方案3】:

您将数据的副本存储到dt。您只是存储了太多以至于机器内存不足。所以你有几个选择:

增加可用内存。 减少要检索的数据量。

要增加可用内存,您可以向机器添加物理内存。请注意,32 位机器上的 .NET 进程将无法访问超过 2GB 的内存(如果您在 boot.ini 中启用 3GB 开关,则为 3GB)因此您可能需要切换到 64 位(机器和进程)如果您希望处理更多的内存。

检索更少的数据可能是要走的路。根据您要实现的目标,您可能能够对数据的子集(甚至可能在单个行上)执行任务。如果您正在执行某种聚合(例如,从数据中生成摘要或报告),您可以使用Map-Reduce。

【讨论】:

使用并不会真正清除内存——它不会触发收集。另外:阅读器只有一个小缓冲区 @MarcGravell:好点子,但它使读者使用的内存符合收集条件,如果结果没有存储在其他地方,则在这种情况下会阻止 OOM。 不,因为阅读器并没有持有所有数据:它是一个流式 API。【参考方案4】:

我认为只是您的内存不足,因为您的 DataTable 因您不断添加的所有行而变得如此之大。

在这种情况下,您可能想尝试不同的模式。

除了将行缓冲在列表(或 DataTable)中,您是否可以简单地生成行,因为它们在到达时可供使用?

【讨论】:

以上是关于C#中IDataReader和DataSet的区别是啥呢?的主要内容,如果未能解决你的问题,请参考以下文章

C# DataSet与DataTable的区别和用法

C# DataSet与DataTable的区别和用法

在 C# 中使用 IDataReader 读取 dbf 文件

引发了“System.OutOfMemoryException”类型的异常。 C# 使用 IDataReader 时

C# - IDataReader 到使用泛型的对象映射

C#中DataSet类的使用