Image Optimization and Database Query Optimization: A Practical Guide to Improve the Speed of WordPress Websites
This article was originally published on the Delicious Brains blog and is reproduced here with permission
You know that a fast website means happier users, better Google rankings and higher conversion rates. You might even think your WordPress site is fast enough: you've checked site performance, from best server setup practices to slow code troubleshooting, and offloading images to CDN, but is that just all?
For dynamic, database-driven websites like WordPress, you may still face a problem: database queries cause website speed to slow down.
In this post, I will walk you through how to identify queries that cause bottlenecks, how to understand the problems with these queries, and other ways to quickly fix and speed up. I'll use an actual query we recently solved that slows down the deliciousbrains.com customer portal.
Query and identification
The first step in fixing slow SQL queries is to find them. Ashley previously praised the Query Monitor debug plugin in his blog, and the database query capability of the plugin makes it a valuable tool for identifying slow SQL queries. This plugin reports all database queries performed during page requests. It allows you to filter them by the code or component (plugin, theme, or WordPress core) that calls them and highlight duplicate and slow queries:
If you don't want to install debug plugins on your production site (maybe you're worried about adding some performance overhead), you can choose to enable MySQL slow query logs, which logs all queries that take some time to execute. This is relatively easy to configure and set the logging location for the query. Since this is a server-level tuning, the performance impact will be less than the debug plugin on the site, but it should be turned off when not in use.
Understanding query questions
After finding the expensive query to improve, the next step is to try to understand what causes the query to slow down. Recently, when developing our website, we found that a query takes about 8 seconds to execute!
SELECT l.key_id, l.order_id, l.activation_email, l.licence_key, l.software_product_id, l.software_version, l.activations_limit, l.created, l.renewal_type, l.renewal_id, l.exempt_domain, s.next_payment_date, s.status, pm2.post_id AS 'product_id', pm.meta_value AS 'user_id' FROM oiz6q8a_woocommerce_software_licences l INNER JOIN oiz6q8a_woocommerce_software_subscriptions s ON s.key_id = l.key_id INNER JOIN oiz6q8a_posts p ON p.ID = l.order_id INNER JOIN oiz6q8a_postmeta pm ON pm.post_id = p.ID AND pm.meta_key = '_customer_user' INNER JOIN oiz6q8a_postmeta pm2 ON pm2.meta_key = '_software_product_id' AND pm2.meta_value = l.software_product_id WHERE p.post_type = 'shop_order' AND pm.meta_value = 279 ORDER BY s.next_payment_date
We use WooCommerce and WooCommerce software to subscribe to a custom version of the plugin to run our plugin store. The purpose of this query is to obtain all subscriptions to customers who we know the customer number. WooCommerce has a rather complex data model, even if the order is stored as a custom post type, the customer's ID (the store for which each customer creates WordPress user) is not stored as a post_author, but as part of the post metadata. The software subscription plugin also creates several custom table connections. Let's take a deeper look at the query.
Use MySQL tools
MySQL provides a convenient DESCRIBE
statement that can be used to output information about the structure of a table, such as its columns, data types, and default values. So if you do DESCRIBE wp_postmeta;
, you will see the following results:
Field | Type | Null | Key | Default | Extra |
---|---|---|---|---|---|
meta_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
post_id | bigint(20) unsigned | NO | MUL | 0 | |
meta_key | varchar(255) | YES | MUL | NULL | |
meta_value | longtext | YES | NULL |
This is cool, but you probably already know. But did you know that the DESCRIBE
statement prefix can actually be used for SELECT
, INSERT
, UPDATE
, REPLACE
, DELETE
, and EXPLAIN
statements? This is more often referred to as its synonym
The following are the results of our slow query:
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | pm2 | ref | meta_key | meta_key | 576 | const | 28 | Using where; Using temporary; Using filesort |
1 | SIMPLE | pm | ref | post_id,meta_key | meta_key | 576 | const | 37456 | Using where |
1 | SIMPLE | p | eq_ref | PRIMARY,type_status_date | PRIMARY | 8 | deliciousbrainsdev.pm.post_id | 1 | Using where |
1 | SIMPLE | l | ref | PRIMARY,order_id | order_id | 8 | deliciousbrainsdev.pm.post_id | 1 | Using index condition; Using where |
1 | SIMPLE | s | eq_ref | PRIMARY | PRIMARY | 8 | deliciousbrainsdev.l.key_id | 1 | NULL |
At first glance, this is not easy to explain. Fortunately, SitePoint friends have written a comprehensive guide on understanding the statement.
The most important column is, which describes how tables are joined. If you see type
, it means that MySQL is reading the entire table from disk, increasing the I/O rate and increasing the CPU load. This is called a "full table scan" (more on this later). ALL
The
column is also a good indication that MySQL must do because it shows the number of rows it looks at in order to find the result. rows
More information available for optimization is also provided. For example, the EXPLAIN
table (pm2
), which tells us that we are using wp_postmeta
because we require the result to be sorted using the filesort
clause in the statement. If we group the queries as well, we will increase the overhead of execution. ORDER BY
Visual Analysis
MySQL Workbench is another convenient and free tool that can be used for such investigations. For databases running on MySQL 5.6 and later, the result of can be output as JSON, which MySQL Workbench converts to a visual execution plan for the statement: EXPLAIN
(alias l) table. wp_woocommerce_software_licences
Solution A full table scan is being performed on a part of the
query, and you should try to avoid this as it uses the non-index column as a connection between the order_id
table and the wp_woocommerce_software_licences
table. This is a common problem with slow queries and can be easily solved. wp_posts
Add index
is part of the very important identification data in the table, and if we query like this, we should indeed add an index on that column, otherwise MySQL will scan the table progressively until the desired row is found. Let's add an index and see what it will do: order_id
SELECT l.key_id, l.order_id, l.activation_email, l.licence_key, l.software_product_id, l.software_version, l.activations_limit, l.created, l.renewal_type, l.renewal_id, l.exempt_domain, s.next_payment_date, s.status, pm2.post_id AS 'product_id', pm.meta_value AS 'user_id' FROM oiz6q8a_woocommerce_software_licences l INNER JOIN oiz6q8a_woocommerce_software_subscriptions s ON s.key_id = l.key_id INNER JOIN oiz6q8a_posts p ON p.ID = l.order_id INNER JOIN oiz6q8a_postmeta pm ON pm.post_id = p.ID AND pm.meta_key = '_customer_user' INNER JOIN oiz6q8a_postmeta pm2 ON pm2.meta_key = '_software_product_id' AND pm2.meta_value = l.software_product_id WHERE p.post_type = 'shop_order' AND pm.meta_value = 279 ORDER BY s.next_payment_date
Learn your query
Check query-connect one by one, sub-query one by one. Did it perform unwanted operations? What optimizations can be made?In this case, we use order_id
to connect the license table to the post table while restricting the statement to the post type of shop_order
. This is to force data integrity to ensure we only use the correct order record. However, it is actually the redundant part of the query. We know that having a software license row in the table with order_id
related to the WooCommerce order in the post table is a safe bet as this is enforced in the PHP plugin code. Let's delete the connection and see if this will improve the situation:
This is not a big savings, but the query is now less than 3 seconds.
Cache
If your server does not enable MySQL query caching by default, it is worth enabling. This means that MySQL will keep records of all executed statements and their results, and if the same statement is subsequently executed, the cached results will be returned. The cache will not expire because MySQL refreshes the cache when changing the table.
Query Monitor found that our query was run 4 times in a page load, and while enabling MySQL query caching is good, repeated reading of the database in one request should actually be avoided altogether. Static caching in PHP code is a simple and very efficient way to solve this problem. Basically, you get them from the database when the first time you request the results of the database query and store them in the static properties of the class, and subsequent calls will return the result from the static properties:
SELECT l.key_id, l.order_id, l.activation_email, l.licence_key, l.software_product_id, l.software_version, l.activations_limit, l.created, l.renewal_type, l.renewal_id, l.exempt_domain, s.next_payment_date, s.status, pm2.post_id AS 'product_id', pm.meta_value AS 'user_id' FROM oiz6q8a_woocommerce_software_licences l INNER JOIN oiz6q8a_woocommerce_software_subscriptions s ON s.key_id = l.key_id INNER JOIN oiz6q8a_posts p ON p.ID = l.order_id INNER JOIN oiz6q8a_postmeta pm ON pm.post_id = p.ID AND pm.meta_key = '_customer_user' INNER JOIN oiz6q8a_postmeta pm2 ON pm2.meta_key = '_software_product_id' AND pm2.meta_value = l.software_product_id WHERE p.post_type = 'shop_order' AND pm.meta_value = 279 ORDER BY s.next_payment_date
The lifespan of the cache is the lifespan of the request, and more specifically, the lifespan of the instantiated object. If you want to persist query results between requests, you need to implement persistent object caching. However, your code needs to be responsible for setting up the cache and invalidating the cache entry when the underlying data changes.
Other methods
We can take other ways to try to speed up query execution, which requires more work than just tuning the query or adding indexes. One of the slowest parts of our query is the table connection work from customer ID to product ID, which we have to do for each customer. What if we only perform all connections once, then what should we do if we only need to get customer data when we need it?
You can de-normalize data by creating a table that stores license data as well as user IDs and product IDs for all licenses, just query the table for a specific customer. You need to rebuild the table when using MySQL triggers INSERT
/UPDATE
/DELETE
/
Similarly, if many connections slow down queries in MySQL, it may be faster to break the query into two or more statements and execute them separately in PHP, and then collect and filter results in your code. Laravel performs similar operations by eagerly loading relationships in Eloquent.
If you have a large amount of data and have many different custom post types, WordPress may be prone to slower queries on the wp_posts
table. If you find it slow to query your post type, consider abandoning the custom post type storage model and using a custom table.
Result
With these query optimization methods, we managed to reduce the query time from 8 seconds to just over 2 seconds and reduce the number of calls from 4 to 1. Note that these query times are recorded in our development environment and will be faster in production environments.
I hope this guide will be helpful for you to track and fix slow queries. Query optimization may seem like a terrible task, but once you try and get some quick success, you will start to be fascinated by it and hope to improve further.
The above is the detailed content of How to Optimize SQL Queries for Faster Sites. For more information, please follow other related articles on the PHP Chinese website!

What’s still popular is the ease of use, flexibility and a strong ecosystem. 1) Ease of use and simple syntax make it the first choice for beginners. 2) Closely integrated with web development, excellent interaction with HTTP requests and database. 3) The huge ecosystem provides a wealth of tools and libraries. 4) Active community and open source nature adapts them to new needs and technology trends.

PHP and Python are both high-level programming languages that are widely used in web development, data processing and automation tasks. 1.PHP is often used to build dynamic websites and content management systems, while Python is often used to build web frameworks and data science. 2.PHP uses echo to output content, Python uses print. 3. Both support object-oriented programming, but the syntax and keywords are different. 4. PHP supports weak type conversion, while Python is more stringent. 5. PHP performance optimization includes using OPcache and asynchronous programming, while Python uses cProfile and asynchronous programming.

PHP is mainly procedural programming, but also supports object-oriented programming (OOP); Python supports a variety of paradigms, including OOP, functional and procedural programming. PHP is suitable for web development, and Python is suitable for a variety of applications such as data analysis and machine learning.

PHP originated in 1994 and was developed by RasmusLerdorf. It was originally used to track website visitors and gradually evolved into a server-side scripting language and was widely used in web development. Python was developed by Guidovan Rossum in the late 1980s and was first released in 1991. It emphasizes code readability and simplicity, and is suitable for scientific computing, data analysis and other fields.

PHP is suitable for web development and rapid prototyping, and Python is suitable for data science and machine learning. 1.PHP is used for dynamic web development, with simple syntax and suitable for rapid development. 2. Python has concise syntax, is suitable for multiple fields, and has a strong library ecosystem.

PHP remains important in the modernization process because it supports a large number of websites and applications and adapts to development needs through frameworks. 1.PHP7 improves performance and introduces new features. 2. Modern frameworks such as Laravel, Symfony and CodeIgniter simplify development and improve code quality. 3. Performance optimization and best practices further improve application efficiency.

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP type prompts to improve code quality and readability. 1) Scalar type tips: Since PHP7.0, basic data types are allowed to be specified in function parameters, such as int, float, etc. 2) Return type prompt: Ensure the consistency of the function return value type. 3) Union type prompt: Since PHP8.0, multiple types are allowed to be specified in function parameters or return values. 4) Nullable type prompt: Allows to include null values and handle functions that may return null values.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

VSCode Windows 64-bit Download
A free and powerful IDE editor launched by Microsoft