Western Mass Hosting's Development Articles

Home / Development / Page 2

Performance Tweaks for Big Wordpress Sites

Tip #1 We backed up the the wp_posts table and then used a simple MySQL command to remove old post revisions. This decreased the table size from 400MB to 120MB: DELETE FROM `wp_posts` WHERE post_type = 'revision' AND post_date NOT LIKE '2012-%' Long-term solution There are WordPress plugins which can…

Cookie Notice

This site utilizes cookies to improve your browsing experience, analyze the type of traffic we receive, and serve up proper content for you. If you wish to continue browsing, you must agree to allow us to set these cookies. If not, please visit another website.

Performance Tweaks for Big Wordpress Sites

Tip #1

We backed up the the wp_posts table and then used a simple MySQL command to remove old post revisions. This decreased the table size from 400MB to 120MB:

DELETE FROM `wp_posts` WHERE post_type = 'revision' AND post_date NOT LIKE '2012-%'

Long-term solution

There are WordPress plugins which can limit the number of revisions per post. We think that the WordPress code should be improved and the revisions should be stored in a different table to maximize speed. You can support this on WordPress bug tracking.

Large number of comments

We need to be extra careful specially with the wp_comments table which has close to 400,000 comments and 320MB. We often find speed issues with MySQL queries which take only a couple of milliseconds on smaller sites.

WordPress 3.2 added a count of comments into the WordPress Admin Bar which shows up for logged in Administrators and Editors when browsing the site.

Counting the comments actually takes a lot of time on our big database. Here’s the query and it’s duration in log:

SQL query for counting of the comments

SELECT comment_approved, COUNT(*) AS num_comments FROM wp_comments GROUP BY comment_approved;

In the above case, it takes 0.3 seconds, while all the other queries are done in 0.05 – 0.001 seconds.

Tip #2

To do this kind of audits use WPDB Profiling plugin for WordPress. It shows you all sorts of information in the site footer and you can turn it on and off as you like.

Beware: this plugin turns off post revisions and autosaves when activated, you need to turn it off once you are finished or change it’s settings.
It’s clearly the slowest query when the site is loading. And this site has up to 20 editors who like to come to the site and read the comments to their articles, so it affects the performance. Keep in mind that this information is shown on multiple places in WordPress Admin Interface.

We created our own queries to do this count. It’s 5 queries instead of 1, but they are faster. Just try to test them:

SELECT COUNT(comment_ID) FROM wp_comments WHERE comment_approved = 'trash<span style="font-family: 'Lucida Grande','Lucida Sans Unicode',sans-serif;">'</span>
SELECT COUNT(comment_ID) FROM wp_comments WHERE comment_approved = 'spam'
SELECT COUNT(comment_ID) FROM wp_comments WHERE comment_approved = '0'<br />
SELECT COUNT(comment_ID) FROM wp_comments WHERE comment_approved = 'post-trash'<br />
SELECT COUNT(comment_ID) FROM wp_comments

The last query counts all the commands, so we subsctract the previous counts. Here are our results – 0.042144 seconds:

SQL query for counting of the comments improved

That’s a big improvement over 0.3 seconds duration with the standard query.

Tip #3

If you want to test above queries, replace SELECT with SELECT SQL_NO_CACHE to make sure no MySQL caching will be used.
We also opened a bug tracking ticket for this on WordPress Trac – Speeding up Dashboard and Comment moderation SQL load.

Finding slow database queries with MySQL tools

Another way of finding the slow queries is using this MySQL command. It’s best used when you have SSH access to the site.

  1. Watch the server load using top.
  2. When you see that mysql process is taking too much of the CPU, just try to list running queries with following command in MySQL console:
mysql> SHOW PROCESSLIST;

+-------+------+---------+------+--------------+------------------------------------------------------------------------------------------------------+
| Id | User | db | Time | State | Info |
+-------+------+---------+------+--------------+------------------------------------------------------------------------------------------------------+
| 59462 | site | site_db | 0 | NULL | SHOW PROCESSLIST |
| 61208 | site | site_db | <strong>62</strong> | Sending data | SELECT ID FROM wp_posts AS a LEFT JOIN (SELECT post_id FROM wp_postmeta WHERE meta_key='...') AS b |
| 61228 | site | site_db | 25 | Locked | UPDATE `wp_postmeta` SET `meta_value` = '1327484262:39' WHERE `post_id` = 66955 AND `meta_key` = '_e |
| 61238 | site | site_db | 16 | Locked | SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (17992) |
| 61241 | site | site_db | 16 | Locked | SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (12931) |
| 61249 | site | site_db | 11 | Locked | SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (34465) |
| 61251 | site | site_db | 11 | Locked | SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (5209) |
| 61257 | site | site_db | 6 | Locked | SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (34465) |
| 61258 | site | site_db | 5 | Locked | SELECT meta_id FROM wp_postmeta WHERE meta_key = '....' AND post_id = 24661 |
| 61262 | site | site_db | 1 | Locked | SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (5367) |
+-------+------+---------+------+--------------+------------------------------------------------------------------------------------------------------+

In the above list, there is some nasty query which is taking 62 (!) seconds to get executed and the other queries are just waiting until it’s finished. Yes, the site was in real trouble when the above list was saved.
There is also an MySQL option called “log slow queries”, but we newer had a success with it.
Here’s the query in it’s full beauty. Since it’s using subqueries, it’s slow and hard to optimize:

SELECT ID FROM wp_posts AS a LEFT JOIN (SELECT post_id FROM wp_postmeta WHERE meta_key='fb') AS b ON a.ID=b.post_id WHERE b.post_id IS NULL;

We re-coded the plugin and this bad query is no longer used. This was some weird query in some old plugin which was running as WordPress Cron job, so it’s not visible in WPDB Profiling which was described above.

Tip #4

If the query seems to complicated, try to move some of the processing into PHP.>

Use indexes!

If you see a slow query, try to use MySQL EXPLAIN command on it. Here’s the query:

SELECT count(*) FROM wp_comments AS c JOIN wp_posts AS p ON c.comment_post_ID = p.ID WHERE c.user_id = '1079' AND c.comment_approved = '1' AND p.post_status = 'publish' AND comment_content REGEXP '[[::]]' = 1

Here’s the output of the EXPLAIN command. Notice the big number in the “rows” column. It means that MySQL has to examine 377,606 rows in the wp_comments table – that’s all the comments on the site.

mysql> EXPLAIN SELECT count(*) FROM wp_comments AS c JOIN wp_posts AS p ON c.comment_post_ID = p.ID WHERE c.user_id = '1079' AND c.comment_approved = '1' AND p.post_status = 'publish' AND comment_content REGEXP '[:asdf:]' = 1;
+-------------+-------+--------+------------------------------------------------------------+------------------+---------+------------------------+--------+-------------+
| select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------------+-------+--------+------------------------------------------------------------+------------------+---------+------------------------+--------+-------------+
| SIMPLE | c | ref | comment_approved,comment_post_ID,comment_approved_date_gmt | comment_approved | 62 | const | 377606 | Using where |
| SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 8 | site.c.comment_post_ID | 1 | Using where |
+-------------+-------+--------+------------------------------------------------------------+------------------+---------+------------------------+--------+-------------+
2 rows in set (0.00 sec)

The SQL query is using user_id in the WHERE clause. And there is no index which would contain this (see possible_keys in above output, you can also execute “SHOW INDEXES IN wp_comments;”).

So we create a new index which will combine two fields from the WHERE clause:

CREATE INDEX userid_approved_index ON `wp_comments` (`user_id`,`comment_approved`)

The table index size will increase a bit, but SQL will search only 1,423 rows when executing our query, because it’s able to use our new index:

mysql> EXPLAIN SELECT count(*) FROM wp_comments AS c JOIN wp_posts AS p ON c.comment_post_ID = p.ID WHERE c.user_id = '1079' AND c.comment_approved = '1' AND p.post_status = 'publish' AND comment_content REGEXP '[:asdf:]' = 1;
+-------------+-------+--------+----------------------------------------------------------------------------------+-----------------------+---------+----------------------------------+------+-------------+
| select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+-------------+-------+--------+----------------------------------------------------------------------------------+-----------------------+---------+----------------------------------+------+-------------+
| SIMPLE | c | ref | comment_approved,comment_post_ID,comment_approved_date_gmt,userid_approved_index | userid_approved_index | 70 | const,const | 1896 | Using where |
| SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 8 | mondoweiss_net.c.comment_post_ID | 1 | Using where |
+-------------+-------+--------+----------------------------------------------------------------------------------+-----------------------+---------+----------------------------------+------+-------------+

Tip #5

When you create a plugin which uses custom SQL queries, have look at the tables and make sure the fields which you used in WHERE or ORDER BY statements are indexed.

Add more indexes to the table if necessary (but then be careful if you ever reinstall WordPress).
Another example would be sorting comments by comment_date. comment_date field is not indexed, but comment_date_gmt is. So use that one and your queries will be faster.

Our Privacy Policy

Last Updated: June 18th, 2025

Introduction

Western Mass Hosting (“we,” “our,” or “us”) respects the privacy of all individuals and organizations that interact with our services. This Privacy Policy establishes our practices regarding the collection, use, disclosure, and protection of personal information for visitors to our website and clients utilizing our managed hosting and WordPress services. By accessing our website or engaging our services, you acknowledge that you have read and understood this policy in its entirety.

Scope and Applicability

This Privacy Policy governs our handling of information collected through our corporate website and in the course of providing managed hosting, WordPress maintenance, and development services. In accordance with global privacy regulations, we serve as a Data Controller for information related to our business operations and client relationships. When processing data on behalf of our clients through hosted services, we act as a Data Processor under applicable data protection laws.

Information We Collect

We collect various categories of information necessary to provide and improve our services. This includes personal contact and payment details provided during account registration, technical information such as IP addresses and device characteristics for security purposes, and records of communications through support channels. For clients utilizing our hosting services, we may process end-user data stored within client websites, though we do not control or monitor the collection practices of such data.

Purpose and Legal Basis for Processing

We process personal information only when we have proper justification under applicable laws. The primary legal bases for our processing activities include the necessity to fulfill contractual obligations to our clients, our legitimate business interests in maintaining and improving our services, and in limited cases, explicit consent for specific marketing communications. We maintain detailed records of processing activities to demonstrate compliance with legal requirements.

Use of Collected Information

The information we collect serves multiple business purposes. Primarily, we use this data to deliver and maintain reliable hosting services, including server provisioning, performance monitoring, and technical support. We also utilize information for business operations such as billing, customer relationship management, and service improvement initiatives. Security represents another critical use case, where we analyze data to detect and prevent fraudulent activity or unauthorized access to our systems.

Data Sharing and Third-Party Disclosures

We engage with carefully selected third-party service providers to support our operations, including cloud infrastructure providers, payment processors, and customer support platforms. These relationships are governed by strict contractual agreements that mandate appropriate data protection measures. We may disclose information when legally required to comply with court orders, government requests, or to protect our legal rights and the security of our services.

International Data Transfers

As a global service provider, we may transfer and process data in various locations worldwide. When transferring personal data originating from the European Economic Area or other regulated jurisdictions, we implement appropriate safeguards such as Standard Contractual Clauses and rely on adequacy decisions where applicable. Our subprocessors, including AWS Lightsail, maintain robust compliance certifications to ensure the protection of transferred data.

Data Retention Practices

We retain personal information only for as long as necessary to fulfill the purposes outlined in this policy. Client account information is typically maintained for five years following service termination to comply with legal and financial reporting obligations. Backup data associated with hosting services is automatically purged after thirty days, as specified in our Terms of Service. For data processed on behalf of clients, retention periods are determined by the respective client’s policies and instructions.

Security Measures

We implement comprehensive technical and organizational security measures to protect personal information against unauthorized access, alteration, or destruction. Our security program includes network encryption protocols, regular vulnerability assessments, strict access controls, and employee training on data protection best practices. We maintain incident response procedures to address potential security breaches and will notify affected parties where required by law.

Individual Rights

Individuals whose personal data we process may exercise certain rights under applicable privacy laws. These rights may include requesting access to their information, seeking correction of inaccurate data, requesting deletion under specific circumstances, and objecting to particular processing activities. We have established procedures to handle such requests in accordance with legal requirements, typically responding within thirty days of receipt. Requests should be submitted to our designated Data Protection Officer through the contact information provided in this policy.

Cookies and Tracking Technologies

Our website employs various technologies to enhance user experience and analyze site performance. Essential cookies are used for basic functionality and security purposes, while analytics cookies help us understand how visitors interact with our site. Marketing cookies are only deployed with explicit user consent. Visitors can manage cookie preferences through their browser settings or our cookie consent tool.

Policy Updates and Notifications

We periodically review and update this Privacy Policy to reflect changes in our practices or legal obligations. Material changes will be communicated to affected clients through email notifications at least thirty days prior to implementation. Continued use of our services following such notifications constitutes acceptance of the revised policy.

Contact Information

For questions or concerns regarding this Privacy Policy or our privacy practices, please contact our Data Protection Officer at info@westernmasshosting.com or by mail at:

Western Mass Hosting
22 Orlando. St.,
Feeding Hills, MA 01030.

We take all privacy-related inquiries seriously and will respond promptly to legitimate requests. For clients with specific data processing agreements, please reference your contract for any additional terms that may apply to our handling of your data.