Русский / English

10 Tips to improve Linq2Sql performance

вторник, 23 декабря 2008 00:42 by tunnel
Если вы собираетесь использовать LINQ в проектах, стоит узнать, как ускорить работу этой технологии.

По пунктам:
  1. Отключить ObjectTracking — у нас уже используется.
  2. Разнести не связанные таблицы по разным датаконтекстам. Сокращение размера датаконтекста позволит уменьшит количество используемой памяти и операций для контроля изменений объектов.
  3. Использовать CompiledQuery — думаю, прирост будет, только вот какой? Тут можно посмотреть результаты тестирования compiled vs uncompiled запросов на LINQ
    В двух словах — прирост есть, в зависимости от частоты похожих запросов от 10% до 70%

    Пример компилированного запроса:
    Func<NorthwindDataContext, IEnumerable<Category>> func =
      CompiledQuery.Compile<NorthwindDataContext, IEnumerable<Category>>
      ((NorthwindDataContext context) => context.Categories.
       Where<Category>(cat => cat.Products.Count > 5));


    * This source code was highlighted with Source Code Highlighter.


    Далее, можно создать статический класс с набором этих компилированных запросов:
    /// <summary>
    /// Utility class to store compiled queries
    /// </summary>
    public static class QueriesUtility
    {
     /// <summary>
     /// Gets the query that returns categories with more than five products.
     /// </summary>
     /// <value>The query containing categories with more than five products.</value>
     public static Func<NorthwindDataContext, IEnumerable<Category>>
      GetCategoriesWithMoreThanFiveProducts
      {
       get
       {
        Func<NorthwindDataContext, IEnumerable<Category>> func =
         CompiledQuery.Compile<NorthwindDataContext, IEnumerable<Category>>
         ((NorthwindDataContext context) => context.Categories.
          Where<Category>(cat => cat.Products.Count > 5));
        return func;
       }
      }
    }


    * This source code was highlighted with Source Code Highlighter.

    Использование же этого класса будет следующим:
    using (NorthwindDataContext context = new NorthwindDataContext())
    {
     var categories = QueriesUtility.GetCategoriesWithMoreThanFiveProducts(context);
    }


    * This source code was highlighted with Source Code Highlighter.

    Кроме того, поддержание многих запросов в одном месте позволит избежать дублирование кода и более легкую его поддержку

  4. Использовать DataLoadOptions.AssociateWith — смысл в том чтобы не использовать LazyLoading, а грузить связанные таблицы сразу. Но грузить не все данные, а лишь по определенному условию.

    using (NorthwindDataContext context = new NorthwindDataContext())
    {
     DataLoadOptions options = new DataLoadOptions();
     options.AssociateWith<Category>(cat=> cat.Products.Where<Product>(prod => !prod.Discontinued));
     context.LoadOptions = options;
    }


    * This source code was highlighted with Source Code Highlighter.

  5. Использовать Optimistic concurrency — добавить в каждую таблицу поле типа TimeStamp — таким образом сам LINQ будет отвечать за concurrency. Кроме того, используя такой подход, можно передавать entity из одного датаконтекст. Если же приложению Optimistic Concurrency не нужна — ее можно отключить. В свойствах Entity в дизайнере выставить UpdateCheck равным UpdateCheck.Never
  6. Мониторить запросы, которые генерирует LINQ. Большинство запросов будет генерироваться на лету, поэтому, как большинство генераторов-дизайнеров от MS, LINQ может сгенерировать не совсем оптимальный запрос — подтягивать лишние колонки, к примеру. Логирование делается очень просто —
    using (NorthwindDataContext context = new NorthwindDataContext())
    {
     context.Log = Console.Out;
    }


    * This source code was highlighted with Source Code Highlighter.

    У себя на работе мы используем DataContextManager, через который создаем все датаконтексты, поэтому привязать логгирование ко всему приложению будет еще проще:
    internal static class DataContextManager
      {
        public static DataContextType Create<DataContextType>(bool readOnlyAccess)
          where DataContextType : DataContext, new()
        {
          DataContextType dc = new DataContextType();
       //DebugWriter is a TextWriter that writes to DebugInfo.txt file
       dc.Log = Common.Logging.Logger.DebugWriter;
          dc.ObjectTrackingEnabled = !readOnlyAccess;
          dc.DeferredLoadingEnabled = false;
          return dc;
        }
      }


    * This source code was highlighted with Source Code Highlighter.


  7. Использовать метод Attach только тогда, когда это действительно нужно. Например, не использовать AttachAll для коллекций, а проверять каждый объект из коллекции на изменения и привязывать/не привязывать его.
  8. Быть более внимательным при работе c контролем изменений объектов. При работе с датаконтекстом в режиме не только чтения простые запросы могут создавать дополнительные затраты ресурсов. Например, очень простой запрос:
    using (NorthwindDataContext context = new NorthwindDataContext())
    {
     var a = from c in context.Categories
     select c;
    }


    * This source code was highlighted with Source Code Highlighter.

    Однако этот запрос будет тратить больше ресурсов нежели следующий:
    using (NorthwindDataContext context = new NorthwindDataContext())
    {
     var a = from c in context.Categories
     select new Category
     {
      CategoryID = c.CategoryID,
      CategoryName = c.CategoryName,
      Description = c.Description
     };
    }


    * This source code was highlighted with Source Code Highlighter.

    Почему? Потому что в первом все еще продолжает работать Object Tracking, в то время как во втором LINQ просто отдает вам объекты и забывает о них.
  9. Получать только нужное количество строк используя Take и Skip методы. Стандартный сценарий для постраничного просмотра:

    /// <summary>
    /// Gets the products page by page.
    /// </summary>
    /// <param name=”startingPageIndex”>Index of the starting page.</param>
    /// <param name=”pageSize”>Size of the page.</param>
    /// <returns>The list of products in the specified page</returns>
    private IList<Product> GetProducts(int startingPageIndex, int pageSize)
    {
     using (NorthwindDataContext context = new NorthwindDataContext())
     {
      return context.Products
          .Take<Product>(pageSize)
          .Skip<Product>(startingPageIndex * pageSize)
          .ToList<Product>();
      }
    }


    * This source code was highlighted with Source Code Highlighter.


    «Преждевременная оптимизация — корень всех зол». Это сказал еще Дональд Кнут.
    Поэтому будьте внимательны, особенно с использованием CompiledQuery. Запросы LINQ не компилируются, как Regex. Компиляция запроса LINQ создает объект в памяти, в котором уже есть SQL-запрос и делегат для работы с ним.

    В принципе, слова Кнута относятся к любым оптимизациям, поэтому не стоит сломя голову оптимизировать все подряд. Лучший выход — попробовать подход и проверить, приносит ли он реальную пользу.

Оценок нет

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Введение в Microsoft Workflow Foundation

понедельник, 8 декабря 2008 02:35 by tunnel
Хочу предложить вашему вниманию серию статей, посвященных Microsoft Workflow Foundation. Данная технология представляет новый, более высокий, уровень абстракции в программировании под .net. Мы начнем с вводной статьи, описывающей предпосылки возникновения технологии, два основных вида рабочих процессов и средства разработки. В дальнейшем мы более подробно ознакомимся с различными аспектами Microsoft Workflow Foundation.

Заинтересовались — читайте дальше.

Введение


Если оглянуться, то мир вокруг нас — это бесконечная череда сменяющих друг друга процессов. Мы сажаем зерно, оно прорастает, цветет, оставляет потомство, погибает. На его месте вырастает что-то новое. И так день за днем. Люди пытаются описать эти процессы, симулировать их на компьютере, придумывают что-то новое. Для этого создаются различные ментальные модели, которые упрощают описание повседневных процессов. Вводятся уровни абстракции. Например, придумали объектно-ориентированное программирование. С его помощью можно описывать объекты реального мира. Это легко и естественно. Достаточно посмотреть на вещь и в голове уже вырисовывается более или менее точная модель: какими свойствами обладает этот объект, какие действия может совершать.

Но объекты, которые никак не взаимодействуют между собой, не имеют никакого смысла. Жизнь — это движение, зачастую цикличное. С другой стороны в мире существует человек. Он вносит некоторую сумятицу своей разумностью. Многие вещи, которые он делает — непоследовательны. Мотивы не всегда ясны. Сроки не всегда соответствуют ожиданиям. Человек может о чем-то забыть, что-то сделать не так, как задумывал раньше. И в тоже время он тоже оперирует объектами. Будь то объекты реального мира, такие, как камни, цветы, вода, или виртуального: документы, информация, слова.

Именно для описания движения и взаимодействия объектов внутри программ создана технология Microsoft Workflow Foundation. Это связующее звено, которое позволяет создавать взаимодействия, связывающие объекты между собой или процессы, протекающие внутри самих объектов. Workflow Foundation (WF) разделяет все процессы на два основных типа: последовательные процессы (sequential) и процессы, основанные на состояниях (state machine).

Последовательные процессы


Последовательные процессы, в понимании WF, — это такие процессы, которые обычно происходят без вмешательства извне. Также, они занимают относительно немного времени. Хорошим примером такого процесса может послужить копирование файлов из одной папки в другую: мы задали папки в начале процесса, а потом в него не вмешиваемся до завершения. Т.е. это, по сути, отлаженный конвейер. Да, может что-то сломаться и потребовать каких-то действий, но это исключительные ситуации, которые обрабатываются отдельно.

Процессы, основанные на состояниях


Лучший пример процесса, основанного на состояниях, кроется в его переводе. State machine буквально означает государственный аппарат. Это такой процесс, который имеет множество состояний, которые в зависимости от различных событий могут переходить из одного в другое. Все это мы обычно видим в бюрократическом аппарате: государственная страховка, продажа квартиры и т.д. Требуются подписи различных чиновников, которые могут быть в отпуске или на больничном. Такой процесс может длиться очень долго: дни, недели, а то и месяцы. Именно для таких ситуаций создан state-machine workflow.

Что нам дает WF


Давайте теперь посмотрим, что нам дает WF. В первую очередь это наглядность. Все мы постоянно рисуем какие-то схемки, наброски. В более сложных случаях мы детально углубляемся в проектирование, например, рисуем временные диаграммы. Теперь мы можем перенести эти эскизы в Microsoft Visual Stuidio 2008 с помощью встроенного редактора. Вот как это выглядит:



Даже далекий от программирования человек сможет разобраться в том, что происходит на диаграмме.
Но все эти эскизы оторваны от действующей программы, никак с нею не взаимодействуют. Если нам надо изменить течение процесса, то необходимо открыть исходники, вспомнить места, в которых необходимо сделать изменения согласно новому эскизу. Эти задачи позволяет решить WF. Мы можем просто взять и перенести участок кода на другое место. Тут же его скомпилировать и сравнить с исходным вариантом.

Также использование WF помогает более наглядно представить работу системы. Выделить процессы, которые могут быть разделены на составляющие или наоборот, объединены. Также поддерживаются транзакционные системы: можно задать компенсирующий процесс для случая, когда что-то пошло не так. Этот процесс вернет систему в состояние, в котором она находилась до наступления ошибки.

Есть возможность опубликовать процесс в качестве сервиса или веб-сервиса, доступного через интернет. Более того, можно создать так называемый Durable web-service, который сохраняет идентификатор сессии и состояние сервиса в промежутках между вызовами, позволяя выполнять процесс в течение длительного времени, не поддерживая соединение. Вы даже можете остановить процесс, сохранить состояние и запустить его на другом компьютере с того же самого места.

Средства разработки


Наиболее удобным средством разработки является визуальный редактор, встроенный в Visual Studio 2008. Он позволяет быстро и гибко создавать и модифицировать процессы. При этом нет необходимости разбираться в том, как это устроено на низком уровне. Также можно создавать процессы, используя язык разметки XAML или при помощи C#.

Давайте взглянем на основные элементы интерфейса для работы с процессами в студии. Вот как выглядит окно в процессе разработки:



Рассмотрим назначение каждой панели.



Это основной документ, в котором мы моделируем процесс. Сейчас мы видим приглашение перетащить туда какие-нибудь элементы для создания последовательного процесса.



Процесс состоит из базовых элементов, называемых Activity. Они находятся в панели Toolbox под номером два. В ней находится множество элементов. Часть из них вполне понятна по их названию. Например, While или IfElse. ConditionedActivityGroup звучит более загадочно.



Естественно, понадобится панель Properties для настройки всевозможных параметров.



Также очень полезна панель Document Outline, обозначенная цифрой четыре. В ней отображается дерево элементов данного процесса, позволяющее быстро переходить от одного элемента к другому.

Заключение


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

Оценок нет

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Строим семантический веб с помощью .NET

среда, 1 октября 2008 03:55 by multilabel
Есть такие люди, которым всегда хочется не только бежать впереди паровоза, но и тянуть его за собой. Mads Kristensen, разработчик лучшего на сегодняшний день блог-движка на .NET — один из таких людей. Поэтому он не ждет наступления Web 3.0, а активно этот момент приближает. Помимо рассказов, как реализовывать поддержку OpenID, что такое весь этот семантический веб, добавления в Blogengine.NET поддержки APML, FOAF, SIOC, XFN, он еще и взял, да и написал библиотечку, с помощью которой можно добавить все эти непонятные модные вещи в свой проект. Правда, библиотечка находится в зачаточной стадии, реализовано еще далеко не все, но в качестве учебного пособия полезна уже сейчас. Запись в блоге Страница на CodePlex

Текущий рейтинг: 4.7 (3 голосов)

  • Currently 4,666667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Редактор фрагментов кода для Visual Studio

четверг, 25 сентября 2008 01:47 by multilabel

Не так давно компания Microsoft опубликовала релиз и исходный код дизайнера фрагментов кода — Visual Studio Snippet Designer. До этого времени (более трех лет) дизайнер фрагментов кода распространялся только для внутреннего использования, теперь он доступен в свободной для скачивания форме на площадке CodePlex.

Текущий рейтинг: 4.5 (2 голосов)

  • Currently 4,5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5