Есть ли более быстрый способ поиска существования экземпляра в большой коллекции, чем с помощью метода Contains?

#c# #search

#c# #Поиск

Вопрос:

У меня есть консольное приложение C #, которое сохраняет данные в таблицах 2 db, таблице сущностей и таблице отношений. Каждая сущность имеет отношения «Многие ко многим» с другими сущностями. В таблице отношений хранится пара идентификаторов, которые, в свою очередь, являются первичным ключом таблицы сущностей.

Данные в обеих таблицах должны быть уникальными. Первоначально я проверил это, прежде чем вставлять новые индивидуальные записи в хранимую процедуру базы данных. Когда числа начинают увеличиваться в обеих таблицах (> 50 кб в таблице сущностей и> 100 кб в таблице отношений) Я заметил, что производительность действительно начала падать.

Я понял, что обращение к БД для выполнения проверок на наличие дубликатов записей значительно повышает производительность из-за дополнительных затрат на ввод-вывод, поэтому я переработал свой код, чтобы сначала прочитать обе таблицы в памяти, а затем выполнить проверки там. вместо этого. Это повысило производительность, хотя я подозреваю, что она все еще может быть не идеальной. Вот как это выглядит сейчас:

     private IEnumerable<long> _existingUsers = dao.GetUserIds();
    private IEnumerable<Relations> _existingRelations = dao.GetRelations();


                if (!_existingUsers.Contains(inputModel.ID))
                {
                    // db code to create the new Entity record
                }

                Relations rel = new Relations { Node = inputModel.Node, Follower = inputModel.ID };

                if (!_existingRelations.Contains(rel))
                {
                    // db code to create the new Relation entry
                }   
  

Класс отношений:

 public class Relations : IEquatable<Relations>
{
    public long Node { get; set; }
    public long Follower { get; set; }

    public bool Equals(Relations other)
    {
        return (other.Node == this.Node) amp;amp; (other.Follower == this.Follower);
    }
}
  

Через отладчик я вижу, что большая часть времени теперь тратится на определение того, содержит ли коллекция _existingRelations в памяти экземпляр «rel». Это, в свою очередь, многократно вызывает метод Equals класса Relations .

Я подозреваю, что может быть более эффективный способ сделать это, но я не знаю, что это такое.

Комментарии:

1. Отсортирована ли коллекция по ключу? Если да: бинарный поиск. Это словарь / хэш? Отлично: используйте это!

2. @MarcGravell Обе коллекции являются списком<T>

3. и снова: отсортирован ли он? Наличие списка ничего не говорит мне о том, отсортирован ли он

Ответ №1:

Это зависит от конкретной реализации IEnumerable .

Это то, что происходит при вызове contains списка. Поиск в списке всегда перебирал весь список, чтобы найти элемент. Таким образом, нет более быстрого способа его найти.

Если вы вызовете это: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1.contains?view=netcore-3.1 тогда вы получите O(1) , как и в случае HashSet со словарями и.

С другой стороны, hashset не упорядочен.

Комментарии:

1. Обе коллекции реализованы в виде списка<T> . Итак, если я вместо этого использую HashSet<T>, это будет намного быстрее?

2. Хорошо, это снизило мой тестовый пример с 129 до> 86 секунд. Хороший материал, спасибо