List<T> 填充集合性能

Posted

技术标签:

【中文标题】List<T> 填充集合性能【英文标题】:List<T> fill collection performance 【发布时间】:2009-10-14 21:55:37 【问题描述】:

我在填写类型列表时遇到了性能问题。以下是我的简化代码:

         public static List<Product> GetProducts()
         
         List<Product> products = new List<Product>();            
         using (DbQuery query = new DbQuery()) //this is database access class
         

            query.CommandText = "SELECT ProdID, ProdName,Price FROM SomeTable " ;+

            using (IDataReader rdr = query.ExecuteReader())
            
               while (rdr.Read())
               
                  Product prd = new Product();
                  prd.ProdID = DbQuery.ReadInt ( rdr, "ProdID", -1 );
                  prd.ProdName = DbQuery.ReadString(rdr, "ProdName", "");
                  prd.Price = DbQuery.ReadDouble(rdr, "Price", 0);
                  products.Add(prd);
               
            
         
          

我也有简单的 struct Product (ProdID, ProdName,Price)。

我的问题是执行 GetProducts() 需要 4 秒。该查询返回大约 600 条记录,返回结果需要几毫秒,所以我确信填充产品集合需要所有这些时间。我在这里做一些低效的事情吗?请帮忙。 谢谢, 格尔达

【问题讨论】:

【参考方案1】:

您是否尝试在要过滤的字段上放置索引?与没有索引相比,这肯定会加快您的查询速度。

【讨论】:

【参考方案2】:

列表插入非常快。这里一定有其他事情发生。尝试在有和没有 products.Add(prd) 注释掉的情况下计时。我怀疑你会发现它们几乎相同。

这是我解决此问题的方法:一次注释一行,直到您看到性能大幅提升 - 然后您就会找到罪魁祸首。

另一件需要注意的事情:数据库性能不是一成不变的。例如,第一次执行需要 4 秒的查询,第二次执行可能只需要 100 毫秒,因为所有数据都缓存到 RAM 中,因此第二次不需要进行物理 I/O。由于 SQL 会引发很多事情,因此对数据库的第一次查询会很慢。我的建议:总是从热缓存开始,这意味着运行一次代码然后再次运行它,并且只考虑第二次计时。更好的是,运行代码 10 次,然后计时 10 次,然后丢弃前 10 次,取第二次的平均值。

【讨论】:

【参考方案3】:

正如贾斯汀建议的那样,我个人会开始注释掉代码部分,直到找到导致瓶颈的原因。例如,我可能首先让例程只运行以数据库为中心的代码:

public static List<Product> GetProducts()
        
            List<Product> products = new List<Product>();

            using (DbQuery query = new DbQuery())
            
                query.CommandText = "SELECT ProdID, ProdName,Price FROM SomeTable ";

                using (IDataReader rdr = query.ExecuteReader())
                
                    while (rdr.Read())
                    
                        //Product prd = new Product();
                        //prd.ProdID = DbQuery.ReadInt(rdr, "ProdID", -1);
                        //prd.ProdName = DbQuery.ReadString(rdr, "ProdName", "");
                        //prd.Price = DbQuery.ReadDouble(rdr, "Price", 0);
                        //products.Add(prd);
                    
                
            

            return products;
        

通过注释掉创建产品对象并将它们添加到列表中的部分,我可以看到数据库相关代码的运行速度。如果运行速度快于 4 秒,那么我知道这与 Product 对象创建和/​​或对 DBQuery 的调用有关,这些调用需要很长时间才能完成。

这是反复试验,但由于此例程非常简单,因此进行此类分析应该不会花费很长时间。

【讨论】:

【参考方案4】:

如果这是您的瓶颈,我会感到惊讶。我会尝试制作一个具有模拟数据库连接的小测试应用程序。

如果您可以预先确定列表的大小,通常可以做得更好。如果查询有一个合理的最小大小,或者如果您有其他方式知道(或合理猜测)一个好的初始大小,您可能会得到微小的提升。

【讨论】:

【参考方案5】:

从它的声音来看,这一定是数据库性能或延迟问题(如果是远程连接)。

【讨论】:

以上是关于List<T> 填充集合性能的主要内容,如果未能解决你的问题,请参考以下文章

.NET性能优化-快速遍历List集合

C#中的泛型和泛型集合

是否有通用方法通过C#中的反射填充各种泛型集合?

List<t> 集合中的选择方法

Java8自定义条件让集合分组

LitJson的集合解析