← scripts 5 min read

Optimizing MySQL for Magento 2 requires understanding how the database interacts with the application and identifying performance bottlenecks. Below are some examples of useful MySQL queries, joins, and commands that can help optimize Magento 2's performance:

1. Identify Slow Queries

Before you optimize, you need to know what queries are running slowly. Using the MySQL slow query log can help with this. Here’s a query to find the top 5 slow queries from the slow query log:

SELECT
    start_time,
    query_time,
    lock_time,
    rows_sent,
    rows_examined,
    sql_text
FROM
    mysql.slow_log
ORDER BY
    query_time DESC
LIMIT 5;

This gives you insight into which queries are taking the longest to execute, allowing you to prioritize their optimization.

2. Optimize Table Queries

Running large queries on Magento’s database tables can be slow if indexes are not used efficiently. You can use the following query to check the size of a specific table and see if it needs optimization (for example, cleaning up orphaned rows):

SELECT 
    table_name AS "Table", 
    ROUND(((data_length + index_length) / 1024 / 1024), 2) AS "Size in MB"
FROM 
    information_schema.TABLES 
WHERE 
    table_schema = "magento_db" AND table_name = "sales_order";

If the table is large, you may want to clean up old data, add indexes, or optimize the table structure.

3. Add Missing Indexes

Indexes help improve the speed of read operations on large tables. To see which indexes are missing or unused, you can run an EXPLAIN query on problematic SELECT statements. Here’s an example of using EXPLAIN to analyze a common query from Magento’s sales table:

EXPLAIN SELECT * FROM sales_order WHERE customer_id = 1234;

If EXPLAIN reveals a full table scan, you can add an index to speed it up:

ALTER TABLE sales_order ADD INDEX idx_customer_id (customer_id);

This can significantly improve the performance of queries filtering by customer_id.

4. Use Joins Effectively

Magento's database structure involves multiple related tables. Efficient use of JOINs is key to optimizing performance. Here’s an example of a common join query to get customer information along with their orders:

SELECT 
    c.entity_id AS customer_id,
    c.email,
    o.entity_id AS order_id,
    o.created_at,
    o.grand_total
FROM 
    customer_entity AS c
JOIN 
    sales_order AS o 
ON 
    c.entity_id = o.customer_id
WHERE 
    o.created_at > '2024-01-01';

This query joins the customer_entity and sales_order tables to get orders placed after January 1, 2024. Make sure there are proper indexes on customer_id and created_at to optimize this query.

5. Find and Remove Unused Attributes

Magento creates many attributes that may never be used in some installations, adding overhead. You can identify and clean up unused product attributes with the following query:

SELECT 
    ea.attribute_id, ea.attribute_code, COUNT(e.entity_id) AS usage_count
FROM 
    eav_attribute AS ea
LEFT JOIN 
    catalog_product_entity AS e 
ON 
    ea.attribute_id = e.attribute_set_id
GROUP BY 
    ea.attribute_id
HAVING 
    usage_count = 0;

This identifies attributes that are not associated with any products. You can then remove these attributes to reduce database bloat.

6. Optimize SQL JOINs with WHERE Clauses

If you need to retrieve data with multiple conditions, make sure you optimize your JOIN statements by using a WHERE clause efficiently. Here’s an example to fetch order and shipment information:

SELECT 
    o.entity_id AS order_id, 
    o.created_at AS order_date, 
    s.entity_id AS shipment_id,
    s.created_at AS shipment_date
FROM 
    sales_order AS o
LEFT JOIN 
    sales_shipment AS s 
ON 
    o.entity_id = s.order_id
WHERE 
    o.status = 'complete' 
AND 
    o.created_at > '2024-01-01';

The LEFT JOIN fetches all orders and their shipments, but only where the order status is 'complete'. Ensuring proper filtering in the WHERE clause will minimize unnecessary data retrieval.

7. Optimize Group By Queries

Magento uses aggregate queries frequently, especially in reports. These can be slow if not optimized. Here’s an example of grouping sales data by product:

SELECT 
    product_id, 
    SUM(qty_ordered) AS total_qty_sold
FROM 
    sales_order_item
GROUP BY 
    product_id
ORDER BY 
    total_qty_sold DESC
LIMIT 10;

Ensure that product_id and qty_ordered have proper indexing to improve the performance of this aggregate query.

8. Analyze Table Usage

Over time, large Magento stores can accumulate a lot of unnecessary data. Use this query to check the size of each table in the database and find which ones might need maintenance or cleanup:

SELECT 
    table_name, 
    table_rows, 
    data_length, 
    index_length, 
    (data_length + index_length) AS total_size 
FROM 
    information_schema.tables
WHERE 
    table_schema = 'magento_db'
ORDER BY 
    total_size DESC;

This query helps you identify the largest tables, which can then be reviewed for optimization or cleanup.

9. Partitioning Large Tables

For very large Magento 2 databases, partitioning tables can improve performance by dividing a table into smaller, more manageable parts. Here’s an example of partitioning the sales_order table by date:

ALTER TABLE sales_order
PARTITION BY RANGE (YEAR(created_at)) (
    PARTITION p2023 VALUES LESS THAN (2024),
    PARTITION p2024 VALUES LESS THAN (2025),
    PARTITION pmax VALUES LESS THAN MAXVALUE
);

This splits the sales_order table into partitions by year, making it faster to query recent data.

10. Use OPTIMIZE TABLE for Table Maintenance

Magento 2’s large database can become fragmented over time. You can run OPTIMIZE TABLE to defragment tables and reclaim unused space:

OPTIMIZE TABLE sales_order;

This command improves performance by reorganizing the table and its indexes.

11. Query Cache

For read-heavy websites, enabling MySQL’s query cache can speed up repeated queries. Check if query caching is enabled:

SHOW VARIABLES LIKE 'query_cache_size';

If it is disabled, you can enable it by setting the query_cache_size and query_cache_type variables in the MySQL configuration file:

query_cache_size = 64M
query_cache_type = 1

This caches results of frequent queries, which is particularly useful for read-heavy workloads.