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 会导致问题吗?
能说一下ADO.NET 和.NET,还有asp.NET的区别吗?