2017-04-06 71 views
1

使用实体框架,我每30秒更新大约300行和9列。以下是我目前正在做的事情。我的问题是,如何让代码更高效?实体框架,更有效地更新多个字段

每隔一段时间,我觉得我的数据库受到冲击,我只是想尽可能地提高效率。

// FOREACH OF MY 300 ROWS 
var original = db.MarketDatas.FirstOrDefault(x => x.BBSymbol == targetBBsymbol); 

if (original != null) 
{ 
    //if (original.BBSymbol.ToUpper() == "NOH7 INDEX") 
    //{ 
    // var x1 = 1; 
    //} 

    original.last_price = marketDataItem.last_price; 
    original.bid = marketDataItem.bid; 
    original.ask = marketDataItem.ask; 

    if (marketDataItem.px_settle_last_dt_rt != null) 
    { 
     original.px_settle_last_dt_rt = marketDataItem.px_settle_last_dt_rt; 
    } 

    if (marketDataItem.px_settle_actual_rt != 0) 
    { 
     original.px_settle_actual_rt = marketDataItem.px_settle_actual_rt; 
    } 

    original.chg_on_day = marketDataItem.chg_on_day; 

    if (marketDataItem.prev_close_value_realtime != 0) 
    { 
     original.prev_close_value_realtime = marketDataItem.prev_close_value_realtime; 
    } 

    if (marketDataItem.px_settle_last_dt_rt != null) 
    { 
     DateTime d2 = (DateTime)marketDataItem.px_settle_last_dt_rt; 

     if (d1.Day == d2.Day) 
     { 
      //market has settled 
      original.settled = "yes"; 
     } 
     else 
     { 
      //market has NOT settled 
      original.settled = "no"; 
     } 
    } 

    if (marketDataItem.updateTime.Year != 1) 
    { 
     original.updateTime = marketDataItem.updateTime; 
    } 

    db.SaveChanges(); 
} 

看什么被打在调试器...

SELECT TOP (1) 
[Extent1].[MarketDataID] AS [MarketDataID], 
[Extent1].[BBSymbol] AS [BBSymbol], 
[Extent1].[Name] AS [Name], 
[Extent1].[fut_Val_Pt] AS [fut_Val_Pt], 
[Extent1].[crncy] AS [crncy], 
[Extent1].[fut_tick_size] AS [fut_tick_size], 
[Extent1].[fut_tick_val] AS [fut_tick_val], 
[Extent1].[fut_init_spec_ml] AS [fut_init_spec_ml], 
[Extent1].[last_price] AS [last_price], 
[Extent1].[bid] AS [bid], 
[Extent1].[ask] AS [ask], 
[Extent1].[px_settle_last_dt_rt] AS [px_settle_last_dt_rt], 
[Extent1].[px_settle_actual_rt] AS [px_settle_actual_rt], 
[Extent1].[settled] AS [settled], 
[Extent1].[chg_on_day] AS [chg_on_day], 
[Extent1].[prev_close_value_realtime] AS [prev_close_value_realtime], 
[Extent1].[last_tradeable_dt] AS [last_tradeable_dt], 
[Extent1].[fut_notice_first] AS [fut_notice_first], 
[Extent1].[updateTime] AS [updateTime] 
FROM [dbo].[MarketDatas] AS [Extent1] 
WHERE ([Extent1].[BBSymbol] = @p__linq__0) OR (([Extent1].[BBSymbol] IS NULL) AND (@p__linq__0 IS NULL)) 

看来它更新同样的事情多次,如果我理解正确的。

UPDATE [dbo].[MarketDatas] 
SET [last_price] = @0, [chg_on_day] = @1, [updateTime] = @2 
WHERE ([MarketDataID] = @3) 

UPDATE [dbo].[MarketDatas] 
SET [last_price] = @0, [chg_on_day] = @1, [updateTime] = @2 
WHERE ([MarketDataID] = @3) 
+0

为什么你认为它更新了同样的事情?你错过了'UPDATE' SQL中的参数吗? –

回答

2

你可以减少这2次往返。

  1. 不要在回路中调用SaveChanges()。将它移到外面并在处理完所有内容后调用它。
  2. 以这种方式编写select,以便一次检索所有原件并将它们推送到内存集合,然后从中更新/插入每个项目。

代码

// use this as your source 
// to retrieve an item later use TryGetValue 
var originals = db.MarketDatas 
    .Where(x => arrayOftargetBBsymbol.Contains(x.BBSymbol)); 
    .ToDictionary(x => x.BBSymbol, y => y); 

// iterate over changes you want to make 
foreach(var change in changes){ 
    MarketData original = null; 

    // is there an existing entity 
    if(originals.TryGetValue(change.targetBBsymbol, out original)){ 
     // update your original 
    } 
} 

// save changes all at once 
db.SaveChanges(); 
+0

只是所以我跟着你,你抓住所有原来的,就像你有以上,然后更新该var原件中的值...那么你如何推这个原始覆盖数据库? – solarissf

+0

@solarissf - 调用'SaveChanges'但在循环外部。 'DbContext'默认跟踪所有检索到的实体,因此在循环中进行更改,然后在循环调用SaveChanges之后,它会将所有更改推回存储。 – Igor

+0

@solarissf - 我更新了我的代码,也许这对你更清楚? – Igor

1

你只能在你的foreach循环后执行“db.SaveChanges”。它认为你会完全按照你的要求去做。

+1

帮助,但我也改变了我的代码,如@Igor所述。 – solarissf

1

看来它多次更新相同的东西,如果我对 了解正确。

实体框架为每个要更新的实体执行数据库往返。

只要检查参数值,它们会不同。

我怎样才能使代码更高效

的主要问题是当前的解决方案是不可扩展的。

当您只有几个实体进行更新时,它会很好地工作,但会变得越来越糟,批次中要更新的项目数量会增加。

在数据库中制作这种逻辑通常比较好,但也许你不能这样做。


免责声明:我的项目Entity Framework Extensions

这个库可以通过允许您一次保存的倍数实体代码更高效的所有者。所有批量操作的支持:

  • BulkSaveChanges
  • BulkInsert
  • BulkUpdate
  • BulkDelete
  • BulkMerge
  • BulkSynchronize

实施例:

// Easy to use 
context.BulkSaveChanges(); 

// Easy to customize 
context.BulkSaveChanges(bulk => bulk.BatchSize = 100); 

// Perform Bulk Operations 
context.BulkDelete(customers); 
context.BulkInsert(customers); 
context.BulkUpdate(customers); 

// Customize Primary Key 
context.BulkMerge(customers, operation => { 
    operation.ColumnPrimaryKeyExpression = 
     customer => customer.Code; 
}); 
+0

谢谢乔纳森 – solarissf