C # LINQ и вычисления с использованием больших наборов данных - PullRequest
5 голосов
/ 24 августа 2011

Это скорее технический вопрос «как» или «лучший подход».

У нас есть текущее требование извлекать записи из базы данных, помещать их в список «в памяти» изатем выполните серию вычислений над данными, то есть максимальные значения, средние значения и некоторые более специфические пользовательские статистические данные.

Получение данных в списке «в памяти» не является проблемой, так как мы используем NHibernate какнаш ORM, и он делает отличную работу по извлечению данных из базы данных.Совет, который я ищу, заключается в том, как лучше всего выполнять вычисления для результирующего списка данных.

В идеале я хотел бы создать метод для каждой статистики, MaximumValue (), AverageValueUnder100 (), MoreComplicatedStatistic () и т. Д. И т. Д.Конечно, передавая необходимые переменные каждому методу и возвращая результат.Этот подход также сделает модульное тестирование быстрым и обеспечит нам превосходный охват.

Будет ли снижение производительности, если мы выполним запрос LINQ для каждого вычисления, или необходимо объединить столько вызовов для каждого статистического метода, скольконесколько запросов LINQ, насколько это возможно.Например, не имеет особого смысла передавать список данных методу AverageValueBelow100, а затем передавать весь список данных другому методу AverageValueBelow50, когда их можно эффективно выполнить одним запросом LINQ.

КакМожем ли мы достичь высокого уровня детализации и разделения без ущерба для производительности?

Любой совет ... достаточно ли ясен вопрос?

Ответы [ 3 ]

1 голос
/ 24 августа 2011

Я не согласен, что лучше всего "делать все это в базе данных".

Хорошо написанные запросы Linq приведут к выполнению хороших SQL-запросов к базе данных, что должно быть достаточно хорошим с точки зрения производительности (если вы не собираетесь делать что-то вроде dwh). Это предполагает, что вы используете провайдера Linq для NHibernate, а не Linq to Objects.

Выглядит хорошо, вы можете легко изменить его и сохранить свою бизнес-логику в одном месте.

Если это слишком медленно для ваших нужд, вы можете проверить созданный код SQL и настроить ваши запросы linq, попытаться предварительно скомпилировать их, и в конце вы все равно можете вернуться к написанию любимых хранимых процедур - и начать распространите свою бизнес-логику повсюду.

Будет ли удар по производительности? Да, вы можете потерять несколько миллисекунд, но стоит ли это цена, которую вы должны заплатить за разделение вашей логики?

1 голос
/ 24 августа 2011

В зависимости от сложности расчета, может быть лучше сделать это в базе данных.Если вам очень сложно представить его в виде объектов и подвергнуть этим накладным расходам, вы можете избежать нескольких итераций в наборе результатов.Вы можете рассмотреть возможность использования Aggregate.См. http://geekswithblogs.net/malisancube/archive/2009/12/09/demystifying-linq-aggregates.aspx для обсуждения, если это.Вы сможете выполнить модульное тестирование каждого агрегата отдельно, но затем (потенциально) спроецировать несколько агрегатов за одну итерацию.

0 голосов
/ 24 августа 2011

Чтобы ответить на вопрос «Я хотел бы создать метод для каждой статистики», я бы предложил вам создать своего рода класс статистиков. Вот некоторый псевдокод, чтобы выразить идею:

class Statistician
{
    public bool MustCalculateFIRSTSTATISTIC { get; set; }   // Please rename me!
    public bool MustCalculateSECONDSTATISTIC { get; set; }  // Please rename me!

    public void ProcessObject(object Object) // Replace object and Rename
    {
        if (MustCalculateFIRSTSTATISTIC)
            CalculateFIRSTSTATISTIC(Object);

        if (MustCalculateFIRSTSTATISTIC)
            CalculateSECONDSTATISTIC(Object);
    }

    public object GetFIRSTSTATISTIC() // Replace object, Rename
    { /* ... */ }
    public object GetSECONDSTATISTIC() // Replace object, Rename
    { /* ... */ }

    private void CalculateFIRSTSTATISTIC(object Object) // Replace object
    { /* ... */ }
    private void CalculateSECONDSTATISTIC(object Object) // Replace object
    { /* ... */ }
}

Если бы мне пришлось это сделать, я, вероятно, попытался бы сделать это универсальным и использовать коллекции делегатов вместо методов, но, поскольку я не знаю ваш контекст, я оставлю это так. Также обратите внимание, что я использовал только члены Object класса объекта, но это только потому, что я не предлагаю вам использовать DataRows, Entities или что-то еще; Я оставлю это другим людям, которые знают больше меня по этому вопросу!

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