SharePoint / Guide 8

Performance: warm-up and caching

Warm-up scripts, the object cache, the BLOB cache and the page output cache.

Most SharePoint Server performance complaints come down to four things: cold application pools, publishing features working without their caches, static files read from SQL on every request, and pages rendered again for every user. This guide covers the fixes: warm-up scripts, the object cache, the BLOB cache and the page output cache.

Which cache does what

Warm-up Object cache BLOB cache Page output cache
Solves Slow first page after a recycle Repeated reads of the same list items, navigation and queries Static files read from SQL The same page rendered again and again
Stores Nothing; it pre-loads Objects in the web server's memory Files on the web server's disk Rendered HTML in memory
Needs publishing features No Yes No (SharePoint Server, not Foundation) Yes
Best for Every farm Publishing and portal sites Portals, sites with images and video Anonymous and read-mostly publishing sites

Warm-up: remove the slow first hit

IIS recycles each application pool regularly (by default once a day). The next request after a recycle has to load and compile SharePoint's assemblies and pages, which can take 30 seconds or more. Whoever makes that request, often the first user in the morning, pays for it.

A warm-up script requests the important pages right after the recycle, so users never see a cold server.

  1. Set a predictable recycle time. In IIS Manager, for each SharePoint application pool, open Recycling and use a specific time outside business hours (for example 2:00 AM) instead of a fixed interval.
  2. Schedule the warm-up 10 to 15 minutes later with Task Scheduler, on every web server, running as an account with read access to the sites:

powershell .\Invoke-SPWarmup.ps1 -IncludeSubsites -LogFile D:\Logs\Warmup.csv

Invoke-SPWarmup.ps1 requests the home page of every site collection (and optionally every subsite) plus one application page per web application, and logs the status and time of each request.

  1. Make each server warm itself. Behind a load balancer, a request for https://sharepoint.ravindran.in might go to any server. On each web server, add a hosts file entry pointing the site names at that server's own IP address, so the warm-up hits the local server. Because Windows blocks authenticated requests back to the local machine by default, add the site names to the BackConnectionHostNames registry value on that server (this is safer than turning off the loopback check entirely).

Also run the warm-up after patching, after an IIS reset, and after deploying solutions.

Object cache

The object cache keeps frequently read objects (list items used by navigation, content query web part results, cross-list queries) in each web server's memory. It's part of the publishing infrastructure.

Configure the super user and super reader accounts. The object cache reads content as two special accounts so it can cache one copy for all users and then trim it per user. If they aren't set, SharePoint falls back to slower behaviour and logs warnings (event ID 7362) in the Application event log.

  1. Create two dedicated domain accounts, for example RAVINDRAN\sp-superuser and RAVINDRAN\sp-superreader. Nobody should sign in with them, and they must not be the application pool or farm account.
  2. Give them Full Control and Full Read user policies on the web application, and store them in the web application's properties. Set-SPObjectCacheAccounts.ps1 does both:

powershell .\Set-SPObjectCacheAccounts.ps1 -WebApplication https://sharepoint.ravindran.in ` -SuperUser RAVINDRAN\sp-superuser -SuperReader RAVINDRAN\sp-superreader -WhatIf

  1. Run iisreset on every web server.

Test straight away. If these accounts are wrong (a typo, or an account that doesn't exist), publishing sites can return "access denied" to everyone. Run the script outside business hours and browse the sites immediately afterwards.

Size it. The default is 100 MB per site collection, set in Site Settings > Site collection object cache. The web application-wide limit is the <ObjectCache maxSize="100" /> element in web.config. Increase it for large portals with heavy navigation or many content query web parts.

BLOB cache

The BLOB cache serves images, style sheets, scripts and video from each web server's disk instead of the SQL content database, and tells browsers to cache them. It has its own guide: see BLOB cache: why and how.

Page output cache

The page output cache stores the fully rendered HTML of publishing pages and serves it to the next user who's allowed to see the same version, skipping page rendering entirely. It helps most on anonymous internet sites and read-mostly intranet portals.

  1. In the site collection, go to Site Settings > Site collection output cache and turn it on.
  2. Choose a cache profile. The built-in profiles are: - Public Internet (Purely Anonymous): longest caching, for anonymous sites. - Extranet (Published Site): for authenticated, read-mostly sites. - Intranet (Collaboration Site): shorter caching, varies by user rights. - Disabled.
  3. Optionally allow page layouts and individual sites to override the profile.

Keep it off for collaboration sites where content changes constantly or pages are personalised per user. The web application-wide defaults are in the <OutputCacheProfiles> element of web.config, including varyByRights="true", which keeps users with different permissions from seeing each other's cached pages. Leave that on.

Other quick wins

  • SQL Server: set max degree of parallelism (MAXDOP) to 1 on the SQL instance that hosts SharePoint databases (this is a SharePoint requirement), pre-size databases, and use fixed-size autogrowth rather than percentages.
  • Keep content databases a manageable size, as covered in the SharePoint Server tips.
  • Distributed Cache: give it enough memory and keep it off busy search servers (see the services guide).
  • Find slow pages with the Developer Dashboard, which shows the time spent in each part of a page:

powershell $svc = [Microsoft.SharePoint.Administration.SPWebService]::ContentService $dds = $svc.DeveloperDashboardSettings $dds.DisplayLevel = 'On' # set back to 'Off' when finished $dds.Update()

  • Crawl from a dedicated target so search doesn't slow down users (see the search guide).