search
HomeBackend DevelopmentPHP TutorialHow to Optimize SQL Queries for Faster Sites

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:

How to Optimize SQL Queries for Faster Sites

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

, which will give us detailed information on how statements are executed.

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

How to Optimize SQL Queries for Faster Sites

It automatically draws your attention by coloring the parts of the query by cost. We can immediately see that there is a serious problem with the joining to the

(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

How to Optimize SQL Queries for Faster Sites

Wow, we successfully reduced the query by adding this index for more than 5 seconds, well done!

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:

How to Optimize SQL Queries for Faster Sites

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/

to the license table (or other tables, depending on how the data changes), but this will significantly improve the performance of querying that data .

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!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
The Continued Use of PHP: Reasons for Its EnduranceThe Continued Use of PHP: Reasons for Its EnduranceApr 19, 2025 am 12:23 AM

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: Exploring Their Similarities and DifferencesPHP and Python: Exploring Their Similarities and DifferencesApr 19, 2025 am 12:21 AM

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 and Python: Different Paradigms ExplainedPHP and Python: Different Paradigms ExplainedApr 18, 2025 am 12:26 AM

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 and Python: A Deep Dive into Their HistoryPHP and Python: A Deep Dive into Their HistoryApr 18, 2025 am 12:25 AM

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.

Choosing Between PHP and Python: A GuideChoosing Between PHP and Python: A GuideApr 18, 2025 am 12:24 AM

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 and Frameworks: Modernizing the LanguagePHP and Frameworks: Modernizing the LanguageApr 18, 2025 am 12:14 AM

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.

PHP's Impact: Web Development and BeyondPHP's Impact: Web Development and BeyondApr 18, 2025 am 12:10 AM

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

How does PHP type hinting work, including scalar types, return types, union types, and nullable types?How does PHP type hinting work, including scalar types, return types, union types, and nullable types?Apr 17, 2025 am 12:25 AM

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.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

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

Hot Tools

MantisBT

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

SAP NetWeaver Server Adapter for Eclipse

Integrate Eclipse with SAP NetWeaver application server.

MinGW - Minimalist GNU for Windows

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

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

VSCode Windows 64-bit Download

VSCode Windows 64-bit Download

A free and powerful IDE editor launched by Microsoft