Мне нужно оптимизировать функцию, которая отображает количество аварийных сигналов для системы, которая становится невыносимо медленной, когда она достигает 20 000 аварийных сигналов. (Тревога состоит из тревоги и условия, то есть фактически это 40 000 объектов). Этот номер обновляется каждые 5 секунд.
Теперь, не берите в голову, что единственное, что нужно, это целое число и что предыдущий программист достиг этого путем:
- Загрузка каждого аварийного сигнала и состояния из базы данных при каждом вызове (подтвержденном и неподтвержденном)
- Перебирайте каждую тревогу, чтобы найти неподтвержденные тревоги (с некоторым пользовательским расширением Linq)
- Отправьте этот список неподтвержденных аварийных сигналов и соответствующий список условий в приложение Silverlight
- Сравнить список неподтвержденных сигналов тревоги с кэшированным списком неподтвержденных сигналов тревоги
- Повторите 4. для условий
- Привязать метки к
Alarms.Count
и Conditions.Count
Это, очевидно, вызывает много ненужных накладных расходов, которые я планирую решить, заменив все оператором SQL
SELECT COUNT(*) as UnAckAlarms
FROM Alarms
WHERE AckTime IS NULL
Но нет, мне было интересно, шаг 4.
Там я нашел это:
foreach (var alarm in loadResult.Entities)
{
if (!ActiveAlarms.Contains(alarm.AlarmId))
{
ActiveAlarms.Add(new AlarmInfo
(...)
Тревога - это объект, без хэша, насколько я знаю, и поэтому я удивился ... Является ли bigO для Collection .Contains()
O (n)? И в этом случае, не будет ли в приведенном выше коде O (n ^ 2)? И если я оптимизирую этот код для O (n) или даже O (1) путем замены всей коллекции, получу ли я увеличение скорости на 0,99%? (40000/400000 ^ 2)
Или я должен просто заменить все оператором SQL и переписать основные части приложения?
edit: Итак, некоторые результаты:
До оптимизации: 60+ секунд для общего получения
После удаления ненужных циклов и пользовательских добавлений: 8 секунд. Время загрузки с сервера составляло ~ 7 секунд, поэтому:
После оптимизации на стороне сервера: 0,3 секунды.
Это примерно на 200% больше скорости. :)