ты извращенец, в цикле по одному выбирать записи когда готовый список есть.
вместо
foreach (var p in products)
{
Product existing = db.Products.Where(pr => pr.SomeUniqueId == p.SomeUniqueId).FirstOrDefault();
}
надо делать
var listOfSomeUniqueId = products.Select(a => a.SomeUniqueId);
var listOfExisting = db.Products.Where(b => listOfSomeUniqueId.Contains(b.RoleId));
и далее обходим готовый список существующих в БД записей
foreach (var p in listOfExisting)
{
p.SomeProperty1 = "HuiPizdaDzhigurda";
p.SomeProperty2 = 123;
}
и в конце концов
db.SaveChanges();
сравни скорость с твоими извратами.
кстати чуть не забыл ответить на твои вопросы:
1. потому что каждый раз поднимается в память вся таблица db.Products и в ней ищется одна запись, сборщик мусора не успевает очистить память, а ты сам не озаботился этим вопросом.
2. Думать головой.