Quantcast
Channel: Houndstooth » mysql
Viewing all articles
Browse latest Browse all 2

Advanced WordPress Performance Optimization

$
0
0

Today we are going to go over some more advanced techniques that can provide big gains in WordPress performance optimization, in short, how to make WordPress faster.  Website Performance Optimization has become quite the buzz lately, as it should. It looks like Steve Souders was correct back in 2010 when he predicted this new market in web development.  There are a lot of books, posts and articles floating around with some great tips and tricks to speed up WordPress but I would like to go over a few advanced tune-ups that don’t get the press like W3 Total Cache does.  The performance enhancements we are going to be using in this article:

  • APC (Alternative PHP Cache)
  • MySQL Query Cache
  • Jim Morgan’s crazy .htaccess rewrite for permalinks
  • Gzip Compression
  • Increase Allocated memory to PHP
  • Browser Caching

APC – Alternative PHP Cache

PHP is a great language that powers a huge portion of the web, but just like anything else, it can have some short-comings out of the box.  One enhancement that can be made is by using PHP accelerators, such as APC, an open source, robust framework for caching and optimizing PHP intermediate code.  PHP is not a compiled language, but instead it is what is called an interpreted language.  What APC does is “pre-compiles” PHP for faster loading.  It is an amazing boost in performance without a lot of work.  APC is a PECL extension so you’ll want to follow instructions for installing PECL extensions in your hosting environment.  Because every hosting environment is different (some shared, some dedicated, etc…) it is hard to give a definitive guide to installation, but here are a few examples:

Linux on a dedicated server – where you have full SSH access.

Media Temple Grid Server Installation - a shared hosting example.

Once you have APC installed and running (you can check this by using phpinfo();), you’ll want to configure it’s settings using php.ini.  The configuration we currently use here on Houndstooth and for a few of our other web properties are as follows, the only change you’ll have to make is to your extensions directory path:

#point to your extensions directory
extension_dir=/full/path/lib/php/
extension = apc.so
apc.enabled=1
apc.shm_segments=1
apc.shm_size=128MB
apc.ttl=3600
apc.max_file_size=1M
apc.stat=1

Once you have setup these configurations, restart apache (if you can) and reap the benefits of opcode caching!  This one change resulted in a 22% increase in our page load time.

MySQL Query Cache

Most WordPress websites utilize a lot of redundant queries (think query_posts or WP_Query).  Every time someone hits your blog homepage (possibly multiple people at the same time) MySQL runs a query to all the posts in your database that might look like

SELECT parameter FROM table WHERE parameter...

You get the drift.  Why not cache these queries since they are going to produce the same results over and over again?  The answer is, you should!  To setup MySQL Query Caching you’re going to need to adjust your my.cnf file, normally if you have one it should be in “/etc/my.cnf”. If you dont have one, you can create one.  Edit your my.cnf and set query_cache_type equal to 1, and set the query_cache_size to some value (we are going to set ours to 25mb).  If you are not sure how much RAM you have running on your setup, 25MB is probably a good starting point.  If you have a lot of RAM, you can allocate more to MySQL, but remember, we’re going to be allocating RAM to a few different server resources, so don’t go overboard or you could have memory problems arise which can actually slow down or crash your site.  Here is what you need to add to my.cnf to get this working:

query_cache_type = 1 
query_cache_size = 26214400

After changes you must restart MySQLd.  There are multiple settings and configurations you can adjust to get this working to the best of your liking.  We can’t cover all of them in this blog post so I would highly recommend reading High Performance MySQL from the O’Reilly line of books.  This book will take your MySQL knowledge to the next level and get your database performing unbelievably fast.

Jim Morgan’s crazy .htaccess rewrite for permalinks

This is one of the easiest enhancements we’ll make in this exercise yet one of the most obvious changes one could make.  Why make WordPress run through the .htaccess file twice when rewriting URLs or rewrite URLs at all for static files like JavaScript, CSS or images?  The typical permalinks rewrite looks like this:

# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

That above rule rewrites every URL that get’s passed to it, sometimes needing to be passed through the snippet multiple times. When replaced with the following snippet, the performance gains are impressive.

# BEGIN WordPress

RewriteEngine on
# Unless you have set a different RewriteBase preceding this
# point, you may delete or comment-out the following
# RewriteBase directive:
RewriteBase /
# if this request is for "/" or has already been rewritten to WP
RewriteCond $1 ^(index\.php)?$ [OR]
# or if request is for image, css, or js file
RewriteCond $1 \.(gif|jpg|css|js|ico)$ [NC,OR]
# or if URL resolves to existing file
RewriteCond %{REQUEST_FILENAME} -f [OR]
# or if URL resolves to existing directory
RewriteCond %{REQUEST_FILENAME} -d
# then skip the rewrite to WP
RewriteRule ^(.*)$ - [S=1]
# else rewrite the request to WP
RewriteRule . /index.php [L]

# END wordpress

For more information check out this link to read more. Or read the commented code to see what’s going on.
WordPress Rewrites Fix

Increase Allocated Memory to PHP

Another quick and simple fix is to increase the memory limit in PHP.  This is another one of those changes that you’ll have to use your best judgement on as if you increase the memory limit by too much you could actually see performance hits in your WordPress site.  This is all based on the available RAM on your server.  To be safe, you can probably increase the amount to 128MB and see a noticeable performance increase without interrupting performance from other resources.  The implementation is simple, and there a few different places you can do it.

In the .htaccess file

php_value memory_limit 128M

In the php.ini file (our preferred method as it will increase PHP memory to all applications running on your server)

memory_limit = 128M

In your wp-config.php file

define('WP_MEMORY_LIMIT', '128M');

There are of course a few other ways to go about it, but the 3 listed here are the recommended methods.

Gzip Compression & Browser Caching

These two are probably more well known and I’m sure you’ve heard of Gzip compression and browser caching before.  There are multiple plugins out there that can take care of these for you, but we prefer to not use plugins wherever possible as they add more resources than are usually needed.  If you’re determined to use a plugin, we recommend WP Super Cache.  W3 Total Cache is another option, but I have had issues with this plugin before and do not prefer it.

The reason we have lumped Gzip compression and browser caching together is because there is a simple way to implement both at the same time in the .htaccess file.  The boys over at HTML5 Boilerplate have pre-made a .htaccess setup that accomplishes both of these tasks by just plopping their code in your .htaccess.  You can get it from the HTML5 Boilerplate zip or you can use it from below, we have stripped out all the other HTML5 BP goodness in order to focus on the exercise at hand.

# ----------------------------------------------------------------------
# Gzip compression
# ----------------------------------------------------------------------

  # Force deflate for mangled headers developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping/

      SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
      RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding

  # Compress all output labeled with one of the following MIME-types

    AddOutputFilterByType DEFLATE application/atom+xml \
                                  application/javascript \
                                  application/json \
                                  application/rss+xml \
                                  application/vnd.ms-fontobject \
                                  application/x-font-ttf \
                                  application/xhtml+xml \
                                  application/xml \
                                  font/opentype \
                                  image/svg+xml \
                                  image/x-icon \
                                  text/css \
                                  text/html \
                                  text/plain \
                                  text/x-component \
                                  text/xml

# ----------------------------------------------------------------------
# Expires headers (for better cache control)
# ----------------------------------------------------------------------

# These are pretty far-future expires headers.
# They assume you control versioning with filename-based cache busting
# Additionally, consider that outdated proxies may miscache
#   www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/

# If you don't use filenames to version, lower the CSS and JS to something like
# "access plus 1 week".

  ExpiresActive on

# Perhaps better to whitelist expires rules? Perhaps.
  ExpiresDefault                          "access plus 1 month"

# cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5)
  ExpiresByType text/cache-manifest       "access plus 0 seconds"

# Your document html
  ExpiresByType text/html                 "access plus 0 seconds"

# Data
  ExpiresByType text/xml                  "access plus 0 seconds"
  ExpiresByType application/xml           "access plus 0 seconds"
  ExpiresByType application/json          "access plus 0 seconds"

# Feed
  ExpiresByType application/rss+xml       "access plus 1 hour"
  ExpiresByType application/atom+xml      "access plus 1 hour"

# Favicon (cannot be renamed)
  ExpiresByType image/x-icon              "access plus 1 week"

# Media: images, video, audio
  ExpiresByType image/gif                 "access plus 1 month"
  ExpiresByType image/png                 "access plus 1 month"
  ExpiresByType image/jpeg                "access plus 1 month"
  ExpiresByType video/ogg                 "access plus 1 month"
  ExpiresByType audio/ogg                 "access plus 1 month"
  ExpiresByType video/mp4                 "access plus 1 month"
  ExpiresByType video/webm                "access plus 1 month"

# HTC files  (css3pie)
  ExpiresByType text/x-component          "access plus 1 month"

# Webfonts
  ExpiresByType application/x-font-ttf    "access plus 1 month"
  ExpiresByType font/opentype             "access plus 1 month"
  ExpiresByType application/x-font-woff   "access plus 1 month"
  ExpiresByType image/svg+xml             "access plus 1 month"
  ExpiresByType application/vnd.ms-fontobject "access plus 1 month"

# CSS and JavaScript
  ExpiresByType text/css                  "access plus 1 year"
  ExpiresByType application/javascript    "access plus 1 year"

Some of these are far-expiring headers so you’re going to want to add versioning to your files so that browser doesn’t serve up old files if you update, say, your stylesheets. There are multiple ways to add versioning, but the way we do it here at Houndstooth is by using PHP and getting the file’s modified date and apending it to the source url. Here is what it would look like.

href="[php] echo bloginfo('stylesheet_directory'); [/php]/css/style.css[php] echo '?v=' . filemtime( get_stylesheet_directory() . '/css/style.css'); [/php]"

Of course you should be using wp_enqueue_style and wp_enqueue_script to load up your stylesheets and scripts, but this is just proof of concept. What you will end up with in the browser is something that looks like

href="http://domain.com/css/style.css?v=64654564"

This way, when you update your stylesheet, the ?v=xxxxxxx would change, thus “creating” a new file for the browser to cache.

WordPress Performance Optimization Conclusion

If you take the time to implement all the methods above, you should see considerable increases in page load time and performance.  We’ve compiled some links below to some tools and pages that we referenced in the article.  Feel free to pose questions or alternatives in the comments, we always love to hear how others are making their pages faster!

Links

Steve Souders

Linux on a dedicated server

Media Temple Grid Server Installation

High Performance MySQL

WordPress Rewrites Fix

WP Super Cache

HTML5 Boilerplate

wp_enqueue_style

wp_enqueue_script

Tools and More Reading

Webpagetest.org

Make the Web Faster

Yslow

Chrome Developer Tools


Viewing all articles
Browse latest Browse all 2

Latest Images

Trending Articles





Latest Images