Оптимизация кода: записи Linq и foreach loop 15k - PullRequest
1 голос
/ 06 сентября 2010

это мой код

void fixInstellingenTabel(object source, ElapsedEventArgs e)
{
    NASDataContext _db = new NASDataContext();

    List<Instellingen> newOnes = new List<Instellingen>();

    List<InstellingGegeven> li = _db.InstellingGegevens.ToList();
    foreach (InstellingGegeven i in li) {
        if (_db.Instellingens.Count(q => q.INST_LOC_REF == i.INST_LOC_REF && q.INST_LOCNR == i.INST_LOCNR && q.INST_REF == i.INST_REF && q.INST_TYPE == i.INST_TYPE) <= 0) {
            // There is no item yet. Create one.
            Instellingen newInst = new Instellingen();
            newInst.INST_LOC_REF = i.INST_LOC_REF;
            newInst.INST_LOCNR = i.INST_LOCNR;
            newInst.INST_REF = i.INST_REF;
            newInst.INST_TYPE = i.INST_TYPE;
            newInst.Opt_KalStandaard = false;
            newOnes.Add(newInst);
        }
    }
    _db.Instellingens.InsertAllOnSubmit(newOnes);
    _db.SubmitChanges();
}

, по сути, жест таблицы InstellingGegevens заполнен какой-то процедурой с другого сервера.затем мне нужно проверить, есть ли новые записи в этой таблице, и заполнить новые в Instellingens.

этот код выполняется в течение 4 минут для записей 15k.как мне это оптимизировать?или это единственный способ хранимой процедуры?

этот код выполняется в таймере, запущенном каждые 6 часов.Если хранимая процедура лучше, как я могу использовать это в таймере?

        Timer Tim = new Timer(21600000); //6u
        Tim.Elapsed += new ElapsedEventHandler(fixInstellingenTabel);
        Tim.Start();

Ответы [ 3 ]

3 голосов
/ 06 сентября 2010

Выполнение этого в хранимой процедуре будет намного быстрее.Мы делаем что-то очень похожее, только в таблице около 100 тыс. Элементов, она обновляется каждые пять минут и содержит намного больше полей.Наша работа занимает около двух минут, а затем она обновляет несколько таблиц в трех базах данных, поэтому ваша работа будет разумно занимать всего пару секунд.

Требуемый запрос будет выглядеть примерно так:

create procedure UpdateInstellingens as

insert into Instellingens (
  INST_LOC_REF, INST_LOCNR, INST_REF, INST_TYPE, Opt_KalStandaard
)
select q.INST_LOC_REF, q.INST_LOCNR, q.INST_REF, q.INST_TYPE, cast(0 as bit)
from InstellingGeven q
left join Instellingens i
  on q.INST_LOC_REF = i.INST_LOC_REF and q.INST_LOCNR = i.INST_LOCNR
  and q.INST_REF = i.INST_REF and q.INST_TYPE = i.INST_TYPE
where i.INST_LOC_REF is null

Вы можете запустить процедуру из задания на сервере SQL, вообще не задействуя какое-либо приложение, или вы можете использовать ADO.NET для выполнения процедуры из своего таймера.

2 голосов
/ 06 сентября 2010

Один из способов оптимизировать это - изменить Count(...) <= 0 на Any().Однако еще лучшей оптимизацией было бы получение этой информации в одном запросе вне цикла:

var instellingens = _db.Instellingens
    .Select(q => new { q.INST_LOC_REF, q.INST_LOCNR, q.INST_REF, q.INST_TYPE })
    .Distinct()
    .ToDictionary(q => q, q => true);

(Если подумать, HashSet будет наиболее подходящим здесьно, к сожалению, нет ToHashSet() метода расширения. Вы можете написать свой собственный, если вам нравится!сам, сделав его ленивым-восстановить:

// No need for the List<InstellingGegeven>
foreach (InstellingGegeven i in _db.InstellingGegevens) {
    // ...
}
1 голос
/ 06 сентября 2010

То, что сказал Гуффа, но использование Linq здесь - не лучший курс, если вам нужна производительность. Linq, как и любой другой ORM, жертвует производительностью ради удобства использования. Что обычно является отличным компромиссом для типичных путей выполнения приложений. С другой стороны, SQL очень и очень хорош в операциях, основанных на множествах, так что это действительно хороший способ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...