c# - 80k 列表的糟糕 linq 性能
问题描述
我有一个来自 Web 服务的约 80,000 个项目列表,我需要根据以下内容计算出要同步到本地数据库的项目:
- 将 Web 服务中的缺失数据插入本地数据库
- 更新本地数据库中过时的较新 Web 服务数据
- 如果不再在 Web 服务中返回,则从本地数据库中删除)。
迭代需要 30 到 60 秒,特别是toInsert
在线上。我不认为 80k 有很多记录(TickerV2
结构大约是 10 个小字段,大部分是 int)。
我一定是在做一些可怕的事情,请问有什么想法可以提高性能吗?
public class TickerV2
{
public string Ticker { get; set; } // Ticker is the key by which we operate
public string Name { get; set; }
public Market Market { get; set; }
public Locale Locale { get; set; }
public TickerType Type { get; set; }
public bool Active { get; set; }
public string PrimaryExch { get; set; }
public DateTime Updated { get; set; }
public CurrencyCodes Currency { get; set; }
// note the Market, Locale, CurrencyCode are all enum but not indexed
}
async Task SaveTickersToDatabaseAsync(IEnumerable<TickerV2> web)
{
using var connection = new SqlConnection(this.dbConnectionString);
await connection.OpenAsync();
var db = connection.Query<TickerV2>("SELECT * FROM Tickers").ToList();
var dbHashset = db.Select(x => x.Ticker).ToImmutableHashSet();
var webHashset = web.Select(x => x.Ticker).ToImmutableHashSet();
var toDeleteTickers = dbHashset.Except(webHashset).ToList();
var toInsertTickers = webHashset.Except(dbHashset).ToList();
var toInsert = web.Where(x => toInsertTickers.Contains(x.Ticker)).ToList();
var toUpdate = db
.Join(web, dbData => dbData.Ticker, web => web.Ticker, (db, web) => new { Db = db, Web = web })
.Where(joined => joined.Web.Updated > joined.Db.Updated)
.Select(x => x.Web)
.ToList();
}
使用字典更新
使用下面的方法我得到了巨大的速度提升......我猜以前我们在每次迭代中都在搜索Contains
(这是顺序的??)Where
- 这个陈述是否正确?
代码变为:
var toInsert = new List<TickerV2>();
var webDictionary = web.ToImmutableDictionary(x => x.Ticker);
toInsert.AddRange(from tickerKey in toInsertTickers
select webDictionary[tickerKey]);
但不确定在问题和其他运营商的背景下,这是否是最好的方法?
解决方案
查询可以优化如下。在内存中加载如此多的条目可能会导致内存泄漏。尝试在数据库中应用过滤器,虽然不是数据库专家不能建议查询。我相信不需要转换为哈希集,因为它只是为了比较而导致开销。
IEnumerable<TickerV2> web = new TickerV2[0];
IEnumerable<TickerV2> db = new TickerV2[0];
var entriesMissingFromDb = web.Except(db, new TickerV2Comparer());
var toInsert = db.Join(entriesMissingFromDb, _db => _db.Ticker, _web => _web.Ticker, (_db, _web) => _web)
.ToList();
比较器如下
public class TickerV2Comparer : IEqualityComparer<TickerV2>
{
public bool Equals(TickerV2 x, TickerV2 y)
{
if (ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
return x.Ticker.Equals(y.Ticker);
}
public int GetHashCode(TickerV2 obj)
{
return obj.Ticker.GetHashCode();
}
}
推荐阅读
- javascript - Vue导入导致无法分配给对象错误的只读属性'exports'
- r - 并行化 for 循环时出错
- c++ - << 使用类和命名空间的运算符重载失败
- spring-cloud - 使用 spring-cloud-kubernetes 配置映射依赖项存在的 spring 应用程序启动异常
- redux-saga - Saga 取消反跳动作
- javascript - 渲染 React-native flatList 的问题
- python - 有没有办法在使用 dlib 检测面部标志后选择面部的特定点?
- laravel - Laravel 从关系中排序和/或分组
- c - 只读文件指针中是否需要 fclose()?
- javascript - 来自弹出窗口的 Google Chrome 扩展消息服务工作者