Почему повторное использование DataContext отрицательно сказывается на производительности? - PullRequest
14 голосов
/ 13 июля 2010

После справедливого количества из исследований и некоторых ошибок я изменил свой код так, чтобы он создает новый DataContext каждый раз, когда запрашивается база данных или вставляются данные. И база данных часто запрашивается - для каждой из 250 000 транзакций, которые обрабатываются, база данных запрашивается, чтобы получить идентификатор клиента, идентификатор отдела и категорию до вставки транзакции.

Так что теперь я пытаюсь оптимизировать код, поскольку он обрабатывал всего около 15 транзакций в секунду. Я удалил несколько посторонних запросов, добавил несколько индексов и получил его до 30 / сек. Затем я решил, что, хотя все говорят, что DataContext является легковесным, нужно создать что-то новое 4 раза за транзакцию, поэтому я попытался повторно использовать DataContext. К моему удивлению, я обнаружил, что повторное использование контекста приводит к снижению производительности до 10 транзакций в секунду!

Почему это так? Это потому, что DataContext кэширует объекты в памяти и сначала просматривает свой список в памяти, прежде чем запрашивать базу данных? Так что, если, например, я ищу идентификатор клиента (первичный ключ) для клиента с именем «MCS», а столбец имени клиента имеет кластеризованный индекс для быстрого выполнения запроса к базе данных, то в памяти поиск будет медленнее?

И правда ли, что создание / утилизация такого количества соединений с БД может замедлить процесс или это просто еще одна преждевременная оптимизация? И если это правда, есть ли способ повторно использовать DataContext, но заставить его выполнять фактический запрос к базе данных для каждого запроса linq-to-sql?

Ответы [ 4 ]

15 голосов
/ 13 июля 2010

Вот почему повторное использование DataContext не рекомендуется, из документации MSDN DataContext :

DataContext является источником всех объектов, отображаемых через соединение с базой данных., Он отслеживает изменения, внесенные вами во все извлеченные сущности, и поддерживает «кэш удостоверений», который гарантирует, что сущности, извлеченные более одного раза, представлены с использованием одного и того же экземпляра объекта.

В общем,экземпляр DataContext рассчитан на одну «единицу работы», однако ваше приложение определяет этот термин.DataContext легок и не дорог в создании.Типичное приложение LINQ to SQL создает экземпляры DataContext в области действия метода или как член недолговечных классов, представляющих логический набор связанных операций с базой данных.

Если вы повторно используете DataContext дляпри большом количестве запросов ваша производительность будет снижаться по нескольким возможным причинам:

  1. Если кэш данных в памяти DataContext становится настолько большим, что он должен начать запись в файл подкачки, тогда вашпроизводительность будет зависеть от скорости чтения с HD-диска, и фактически вообще не будет причин использовать кеш.

  2. Чем больше объектов идентичности находится в памяти, тем дольшекаждая операция сохранения занимает.

По сути, вы нарушаете принцип UoW для класса DataContext.

Открытие соединений с базой данных связано с некоторыми накладными расходами,но держать соединение открытым в течение длительного периода времени (что часто также означает блокировку стола) менее предпочтительнов состоянии, чем открыть и закрыть их быстро.

Другая ссылка, которая может или не может вам помочь из MSDN:

Как: повторно использовать соединение между командой ADO.NET и DataContext (LINQ to SQL)

1 голос
/ 13 июля 2010

Не совсем здесь, но рассматривали ли вы какой-то кэш уровня приложения, чтобы найти идентификатор клиента, идентификатор отдела и категорию?Из вашего поста не ясно, сколько таких сущностей существует в вашей системе или что требуется для их получения.

Однако, например, если у вас есть миллион категорий в вашей системе и вынеобходимость поиска их идентификатора по имени категории, хранение словаря имен / идентификаторов в памяти для поиска всегда сохранит вам поездку в базу данных для транзакции, которую вы обрабатываете.Это может значительно улучшить производительность (это предполагает несколько вещей, например, новые питомники не добавляются регулярно).Как правило, поездки в базу данных обходятся дороже, чем операции в памяти.

1 голос
/ 13 июля 2010

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

Кластерный индекс не обязательно самый быстрый, если строка широкая.Наиболее быстрым, вероятно, будет покрывающий некластеризованный индекс, но это действительно не относится к делу.

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

1 голос
/ 13 июля 2010

Даже с кластеризованным индексом поиск в памяти всегда будет быстрее, чем запрос к базе данных - за исключением крайних случаев, таких как 386 против Cray - даже если вы учитываете задержки, связанные с сетью.

Я бы предположил, что ухудшение связано с обработкой DataContext сущностей, которые он отслеживает: повторное использование контекста будет постоянно увеличивать количество отслеживаемых сущностей, и вызов SaveChanges может в конечном итоге потребовать больше времени.

Опять же, это предположение, но я бы начал искать.

...