Почему повторное использование DataContext отрицательно влияет на производительность?

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

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

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

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

Ответы

Ответ 1

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

DataContext является источником всех объекты, сопоставленные по базе данных подключение. Он отслеживает изменения, которые вы для всех восстановленных объектов и поддерживает "тайник идентификации", который гарантирует, что получаемые объекты более одного раза представлены используя тот же экземпляр объекта.

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

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

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

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

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

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

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

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

Ответ 2

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

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

Опять же, это догадка - но там, где я начну искать.

Ответ 3

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

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

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

Ответ 4

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

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