I have an ~80,000 item list from a web service, of which i need to work out the items to synchronize to a local database based on the below:
- Insert missing data from web service in to local db
- Update newer web service data that is stale in local db
- Delete from local db if no longer returned in the web service).
It is taking 30 to 60 seconds to iterate through, specifically on the toInsert line. I dont see 80k to be many records (the TickerV2 structure is about 10 small fields mostly int).
I must be doing something horrendous, any ideas on making this more performant please?
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(); } UPDATE USING DICTIONARY
I got a massive speed increase using the below... I guess previously we were searching for Contains (which is sequential??) on each Where iteration - is this statement correct?
Code becomes:
var toInsert = new List<TickerV2>(); var webDictionary = web.ToImmutableDictionary(x => x.Ticker); toInsert.AddRange(from tickerKey in toInsertTickers select webDictionary[tickerKey]); But not sure if in the context of the question and other operators, if this is the best way?