Ужасная производительность linq со списком 80k - PullRequest
0 голосов
/ 11 июля 2020

У меня есть список из 80 000 элементов из веб-службы, из которых мне нужно разработать элементы для синхронизации с локальной базой данных на основе следующего:

  • Вставить отсутствующие данные из веб-службы в локальную базу данных
  • Обновить новые данные веб-службы, которые устарели в локальной базе данных
  • Удалить из локальной базы данных, если они больше не возвращаются веб-службой).

Итерация занимает от 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]);

Но не уверен, что в контексте вопроса и других операторов, если это лучший способ?

1 Ответ

2 голосов
/ 11 июля 2020

Запросы можно оптимизировать следующим образом. Кроме того, загрузка такого количества записей в память может вызвать утечку памяти. Попробуйте применить фильтр к базе данных, я не эксперт по базам данных, но не могу предложить запрос. Я считаю, что преобразование в хэш-наборы не требуется, поскольку оно вызывает накладные расходы только для сравнения.

        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();

Comparer выглядит следующим образом

    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();
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...