Showing posts with label Optimization. Show all posts
Showing posts with label Optimization. Show all posts

Tuesday, January 27, 2009

HTTPS Performance Tuning

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

HTTPS Performance Tuning

Two Simple Rules for HTTP Caching

Best Practices for Speeding Up Your Web Site

Очень полезные советы собранные все вместе

http://developer.yahoo.com/performance/rules.html


Make Fewer HTTP Requests
Use a Content Delivery Network
Add an Expires or a Cache-Control Header
Gzip Components
Put Stylesheets at the Top
Put Scripts at the Bottom
Avoid CSS Expressions
Make JavaScript and CSS External
Reduce DNS Lookups
Minify JavaScript and CSS
Avoid Redirects
Remove Duplicate Scripts
Configure ETags
Make Ajax Cacheable
Flush the Buffer Early
Use GET for AJAX Requests
Post-load Components
Preload Components
Reduce the Number of DOM Elements
Split Components Across Domains
Minimize the Number of iframes
No 404s
Reduce Cookie Size
Use Cookie-free Domains for Components
Minimize DOM Access
Develop Smart Event Handlers
Choose link over @import
Avoid Filters
Optimize Images
Optimize CSS Sprites
Don't Scale Images in HTML
Make favicon.ico Small and Cacheable
Keep Components under 25K
Pack Components into a Multipart Document

Friday, December 19, 2008

10 Tips to impove Linq2Sql performance

Я думаю, если мы собираемся использовать линк в проектах, стоит узнать, как ускорить работу этой технологии:
  1. Отключить ObjectTracking - у нас уже используется.
  2. DataContextManager.Create<tcontext>(bool readOnly) - если true, то object tracking выключен. Это позволит отключить ненужный в таком случае контроль изменений объектов.

  3. Разнести не связанные таблицы по разным датаконтекстам. Сокращение размера датаконтекста позволит уменьшит количество используемой памяти и операций для контроля изменений объектов.

  4. Использовать 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.

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

  5. Использовать 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.

  6. Использовать Optimistic concurrency - добавить в каждую таблицу поле типа TimeStamp - таким образом сам LINQ будет отвечать за concurrency. Кроме того, используя такой подход, можно передавать entity из одного датаконтекст. Если же приложению Optimistic Concurrency не нужна - ее можно отключить. В свойствах Entity в дизайнере выставить UpdateCheck равным UpdateCheck.Never
  7. Мониторить запросы, которые генерирует 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 = SaM.Dept2.Common.Logging.Logger.DebugWriter;
          dc.ObjectTrackingEnabled = !readOnlyAccess;
          dc.DeferredLoadingEnabled = false;
          return dc;
        }
      }


    * This source code was highlighted with Source Code Highlighter.


  8. Использовать метод Attach только тогда, когда это действительно нужно. Например, не использовать AttachAll для коллекций, а проверять каждый объект из коллекции на изменения и привязывать/не привязывать его.
  9. Быть более внимательным при работе 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 просто отдает вам объекты и забывает о них.

  10. Получать только нужное количество строк используя 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.


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

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




Спасибо.

На основе статьи 10 Tips to Improve Linq2Sql Performance... и собственного опыта.