ADO.Net DataTables 有索引吗?

Posted

技术标签:

【中文标题】ADO.Net DataTables 有索引吗?【英文标题】:Do ADO.Net DataTables have indexes? 【发布时间】:2010-11-09 17:18:33 【问题描述】:

我正在使用 VSTS 2008 + C# + .Net 3.5 + SQL Server 2008 + ADO.Net。如果我使用 ADO.Net 的 DataTable 从数据库加载表,并且在数据库表中,我在表上定义了几个索引。我的问题是,在ADO.Net DataTable上是否有相关的索引(和我在物理数据库表上创建的索引一样)来提高对DataTable的某些操作性能?

提前致谢, 乔治

【问题讨论】:

Note that DataViews do have indexes。 "DataView 的索引在创建 DataView 和修改任何排序或过滤信息时建立。" 【参考方案1】:

实际上,乔治的问题并不像某些人坚持的那样“糟糕”。 (我越来越相信没有“一个坏问题”这样的东西。

我有一个相当大的表,我在 DataTable 对象中加载到内存中。很多时候,在这张表的行上,对各种(和不同的)子集进行了大量处理,我可以很容易地将其描述为 SELECT 子句的“WHERE ...”。现在有了这个 DataTable,我可以运行 Select()——DataTable 类的一个方法——但是效率很低。

最后,我决定加载按特定列排序的DataTable并实现我自己的 快速搜索,而不是使用 Select() 函数。它被证明要快得多,但当然它只适用于那些排序的列。如果 DataTable 有索引,就可以避免麻烦。

【讨论】:

但是很少有开发人员遇到你描述的问题。如果 Microsoft 只为您在 DataTable 类中实现“索引”,那将是浪费时间。 @JohnSaunders 将 DataTable 加载到内存中以用于大量查找似乎不是“极少数开发人员”需要做的事情。考虑到数据库驱动应用程序的范围,这似乎是一件相当普遍的事情。这就是微软实施DataViews which do create indexes的原因。 @bacon 您是否认为“很少有开发人员”需要这样做并不重要。重要的是事实。并且数据库驱动的应用程序使用数据库,而不是内存中的 DataTable 对象。另外,请注意,OP 只是作为新手被混淆了,并且误解了 DataTable 的角色。 @JohnSaunders 因此,如果您必须对预计有 10,000 行的表进行一百万次查找,您建议执行一百万个单独的查询是专业的方法吗?随便吧,伙计。 @bacon 这就是数据库的用途。但是 10,000 行不算什么。如何提前并将其加载到 DataTable 中。但是在数据库表可能有索引的意义上,没有索引。如果查找速度足够快,请使用 DataTable。否则,请考虑使用 Dictionary 或自定义集合对象。【参考方案2】:

不,但可能是的。

您可以使用 DataView 在 DataTable 上设置自己的索引。当您更改表时,DataView 将被重建,因此索引应该始终是最新的。

我为自己的应用做了一些基准测试。我使用 DataTable 来近似 Boost MultiIndexContainer。为了在名为“Author”的列上创建索引,我初始化了 DataTable,然后是 DataView...

_dvChangesByAuthor = 
    new DataView(
        _dtChanges, 
        string.Empty, 
        "Author ASC", 
        DataViewRowState.CurrentRows);

若要按 Author 从表中提取数据,请使用视图的 FindRows 函数...

            dataRowViews = _dvChangesByAuthor.FindRows(author);
            List<DataRow> returnRows = new List<DataRow>();
            foreach (DataRowView drv in dataRowViews)
            
                returnRows.Add(drv.Row);
            

我创建了一个随机的大型 DataTable,并使用 DataTable.Select()、Linq-To-DataSet(通过导出到列表强制执行)和上述 DataView 方法运行查询。 DataView 方法很容易获胜。 Linq 用了 5000 个滴答,Select 用了 26000 个滴答,DataView 用了 192 个滴答...

LOC=20141121-14:46:32.863,UTC=20141121-14:46:32.863,DELTA=72718,THR=9,DEBUG,LOG=Program,volumeTest() - Running queries for author >TFYN_AUTHOR_047<
LOC=20141121-14:46:32.863,UTC=20141121-14:46:32.863,DELTA=72718,THR=9,DEBUG,LOG=RightsChangeTracker,GetChangesByAuthorUsingLinqToDataset() - Query elapsed time: 2 ms, 4934 ticks; Rows=65 
LOC=20141121-14:46:32.879,UTC=20141121-14:46:32.879,DELTA=72733,THR=9,DEBUG,LOG=RightsChangeTracker,GetChangesByAuthorUsingSelect() - Query elapsed time: 11 ms, 26575 ticks; Rows=65 
LOC=20141121-14:46:32.879,UTC=20141121-14:46:32.879,DELTA=72733,THR=9,DEBUG,LOG=RightsChangeTracker,GetChangesByAuthorUsingDataview() - Query elapsed time: 0 ms, 192 ticks; Rows=65

因此,如果您想要在 DataTable 上建立索引,我建议您使用 DataView,前提是您可以处理在数据更改时重新构建索引的事实。

【讨论】:

【参考方案3】:

您可以为数据表创建主键。如果您在主键字段中搜索,过滤器操作会得到很大的提升。看看这个链接:here

【讨论】:

【参考方案4】:

我在来自大型数据表的许多查询中遇到了同样的问题,这些查询不符合主键。

我找到的解决方案是为我想使用的每个索引创建 DataView,然后使用它的 Find 和 FindRows 方法来提取数据。

DataView 在 DataTable 上创建一个内部索引,并为此目的实际上充当索引。

就我而言,我能够将 10,000 个查询从 40 秒缩短到 1 个!!!

【讨论】:

【参考方案5】:

上面的约翰是正确的。 DataTables 在内存结构中是不连贯的。它们不映射到数据库的物理实现。

磁盘上的索引用于加快查找速度,因为您没有所有行。如果您必须加载每一行并扫描它们,它会很慢,所以索引是有意义的。在 DataTable 中,您已经拥有所有行,因此比较已经很快了。

【讨论】:

【参考方案6】:

这里对在 DataTable 上创建索引的隐含问题的正确答案是您不能这样做,但是您可以为 DataTable 创建一个或多个 DataView,根据the doc 将创建一个基于索引关于 DataView 指定的排序:

DataView 构造一个索引。索引包含从表或视图中的一个或多个列构建的键。这些键存储在一个结构中,使 DataView 能够快速有效地找到与键值关联的行。使用索引的操作(例如过滤和排序)可以显着提高性能。 DataView 的索引是在创建 DataView 和修改任何排序或过滤信息时建立的。创建一个 DataView 然后设置排序或过滤信息会导致索引至少构建两次:一次是在创建 DataView 时,另一次是在修改任何排序或过滤属性时。

如果您需要对内存中的 DataTable 进行大量查找,使用带有 Find()FindRows() 方法的 DataView 进行索引键查找可能是最直接和最高效的。特别是,如果您需要对数据进行大量查找和修改,这将避免需要将您的 DataTable 转换为另一个索引类(如 Dictionary),然后再次将其转换回 DataTable。

【讨论】:

【参考方案7】:

其他人已经指出,DataSet 不打算用作数据库系统——只是数据的表示。如果您认为 DataSet 是一个数据库,那么您就大错特错了,可能需要重新考虑您的实现。

如果您需要客户端数据库,请考虑使用 SQL Compact 或 SQL Lite,它们都是免费的可再分发数据库系统,无需单独安装或服务即可使用。如果您需要更全功能的东西,SQL Express 是下一步。

为了帮助澄清,在 .NET 开发中使用 DataSets/Tables 来根据需要临时保存数据。将它们视为针对数据库的 SELECT 查询的结果;它们与 CSV 文件或其他形式的表格数据大致相似——您可以从数据库中将数据拉入其中,处理数据,然后将更改推送回数据库——但它们本身并不是数据库。

如果您出于某种原因需要将大量项目保存在内存中,那么您可能会考虑构建一个轻量级 DTO(数据传输对象,谷歌搜索,它们非常简单)并将它们加载到哈希表。 HashTables 不会为您提供任何形式的关系数据,但在查找方面非常有效。

【讨论】:

感谢 John 和 Yoooder,我在想我以前为什么会感到困惑。我认为即使 DataTable 的初始值是从数据库中的 SELECT 中正常检索的,但我们可以在 DataTable 上发出 select 以从 DataTable 中获取数据子集,这就是为什么我之前感到困惑,这就是为什么我想当我在DataTable上发出SELECT,也许我需要创建索引以提高查询性能,任何cmets?【参考方案8】:

DataTables 有一个 PrimaryKey 字段可以用作索引(无论如何它们已经很快了)。该字段不是从数据库的主键中复制的(尽管这可能很好)。

【讨论】:

【参考方案9】:

我对文档的阅读是,实现此目的的正确方法(如果需要)是使用AsDataView 生成绑定到基础表的DataView(或LinqDataView)。如果您的DataTable 是不变的,那么DataView 可以是静态的,以避免多余的重新索引。

我目前正在调查Linq to DataSet,这个q对我有帮助,所以谢谢。

【讨论】:

【参考方案10】:

如果您(编码人员)指定一个或多个 DataColumns 作为主键,则 DataTables 会被索引。 Interally ADO.NET 使用红黑树来形成此索引,以提供日志时间查找。此主键不会根据数据提供者的任何基础键自动设置。

【讨论】:

DataTables 没有数据提供者。【参考方案11】:

乔治,

答案是否定的。

实际上,可以在内部使用某种索引,但仅作为实现细节。例如,如果您创建了一个外键约束,那么这可能是由索引辅助的。但这对开发人员来说并不重要。

【讨论】:

乔治,你到底为什么认为需要来提高性能? 这意味着这是一个糟糕的问题,乔治。你假设太多,在这个过程中浪费了你的时间。 DataSet/DataTable 是一种与关系数据库模型相匹配的断开连接的内存结构。那是模型,George,而不是实现,这就是索引。所以,不,不要在性能问题发生之前担心它们,否则你会发现你担心的是错误的问题。并且不用担心 DataTable 的性能问题。 顺便说一句,这是你吗:social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/… George,我的建议是,在您发现性能问题之前,不要再考虑 DataTable 或其他任何东西的性能问题。当然,我不打算在这个问题上花更多的心思。 乔治,优化什么?你有性能问题吗?此外,您似乎认为 DataTable 是一个内存数据库。它不是。没有优化。没有什么可优化的。

以上是关于ADO.Net DataTables 有索引吗?的主要内容,如果未能解决你的问题,请参考以下文章

带有 ADO .NET 的 ASP .NET MVC 会导致问题吗?

WCF REST 与 ADO.NET 数据服务

ADO.NET 实体框架教程 [关闭]

能说一下ADO.NET 和.NET,还有asp.NET的区别吗?

这两个到 ADO.NET 的连接是不是相同(启用了连接池)?

ADO.NET 包含哪些内容