用于组合数据的实体框架算法

Bra*_*son 6 database sql-server linq-to-entities entity-framework

这属于我继承的项目,不能更改表结构或数据访问模型.我被要求优化用于将数据插入数据库的算法.

我们在表T中有一个数据集.从那里,我们拉出一个我们将调用A的集合.我们还查询XML feed并得到一个我们将调用X的集合.

  • 如果X中的值在A中,则必须更新A中的记录以反映X.record的数据
  • 如果X中的值不在A中,则必须将X.record插入到A中
  • 如果A中的值不在X中,则A.record必须保留在A中
  • 必须对所有记录完全迭代X,并且必须更新A.

所有这些更改都需要插回到数据库中.

设置的算法执行以下操作:

Query XML into a LIST
foreach over the XML LIST
    look up foreach.item in A via LINQ (i.e. query = from record in A where
                                                         record.GUID == foreach.item.GUID
                                                         select record)
    if query.Count() == 0
        insert into A (via context.AddToTableName(newTableNameObject)
    else
        var currentRecord = query.First()
        set all properties on currentRecord = properties from foreach.item
        context.SaveChanges()
Run Code Online (Sandbox Code Playgroud)

我知道这不是最理想的.我试图将A放入foreach循环之外的对象(称为queryA),以便将查询移动到内存而不是访问磁盘,但在考虑完之后,我意识到数据库已经在内存中了.

已经将计时器对象添加到算法中,很明显,花费最多时间的是SaveChanges()函数调用.在某些情况下,它是20毫秒,而在其他一些情况下,在可解释的情况下,它会跳到100毫秒.

我宁愿只调用SaveChanges()一次.考虑到我对EF(最好是最薄的)知识的深度以及无法更改表结构并且必须保留不在X中的A的数据的限制,我无法弄清楚如何做到这一点.

建议?

Lad*_*nka 5

我认为使用实体框架不会提高性能:

查询

  • 通过单独的查询加载每个记录是不好的
  • 您可以通过在同一查询中加载多个记录来提高性能。例如,您可以使用||加载一小批记录 条件或Contains(如INSQL)。Contains仅.NET 4.0支持。
  • 另一个改进可以是用存储过程和表值参数替换查询,以将所有向导与X.Guids一起传递给SQL Server join A并获取结果。表值参数仅在SQL 2008和更高版本上受支持。

数据修改

  • 每次修改后,您都不必调用SaveChanges。您可以在foreach循环之后调用它,它仍然可以工作。它会在一次交易中通过所有修改,但是通过这种操作您将不会获得任何性能提升,根据此答案,它可以为您带来巨大的提升。
  • EF不支持命令批处理,因此每次更新或插入总是需要单独往返数据库。使用EF修改数据时,除了实现整个新的EF ADO.NET提供程序(就像启动一个新项目一样)之外,没有其他方法可以解决此问题。
  • 同样,解决方案是通过使用带有表值参数的存储过程来减少往返次数
  • 如果您的数据库还使用该GUID作为主键和聚集索引,则在每次插入 =修改磁盘上的数据之后对索引重新排序会导致另一个性能下降。

问题不在于算法,而在于您处理数据的方式以及用于处理数据的技术。实体框架不是数据泵的好选择。您应该将这些信息带给老板,因为提高性能意味着您的应用程序将进行更复杂的更改。这不是您的错,也不是编写应用程序的程序员的错。这是EF的一项功能,该功能不是很为人所知,而且据我所知,在任何MS最佳实践中都没有明确说明。