Query Optimization in MariaDB

This is a follow-up post to Deep Dive into Advanced SQL Techniques with Examples. While this article focus on MariaDB, the concepts outlined here may be applied to other RDBMS.

Query optimization is the elusive process of improving the efficiency and performance of SQL queries to reduce execution time, minimizes resource usage, and enhances overall database performance.

You cannot improve what you cannot measure, this article assumes query logging is enabled, see Slow Query Log. This enables us to identify queries that are taking longer to execute and those that are processing a larger number of data rows.

1. Query Execution Plan

Provides crucial information for identifying bottlenecks in a query by showing how a query will be executed, which indexes will be used, the order of table access, and the estimated number of rows that will be processed.

Sample interpretation of the second row from the output:

  • Table: c: Refers to the countries table.
  • Type: index: The query scans the entire index, which is more efficient than scanning the table.
  • Key: region_id: This index is being used.
  • Rows: 239: The query scans 239 rows.
  • Extra: Using index: The index covers all the columns needed by the query, so the table itself isn’t accessed.

2. Indexes

Helps to quickly locate rows without scanning the entire table e.g. primary keys, unique indexes, full-text indexes, and spatial indexes. It is not just enough to choose the right type of index but also to index the correct (set of?) columns.

This example reduces query time by approximately 91.67% from 0.012 seconds to 0.001 seconds by simply adding an index.

3. Join Optimization

When joining multiple tables, the DB can optimize the join order and method e.g., nested loops, hash joins). Joins should use indexed columns and unnecessary columns should be excluded from the result set to reduce the processing time.

In this example we reduce query time from 0.020 seconds to 0.012 ~40.0% by indexing the join columns.

4. Query Rewrite

Sometimes rewriting a query may lead to better performance e.g. replacing a subquery with a JOIN or using EXISTS instead of IN. There is also automatic query rewrite through tool like Optimizer Switch.

5. Partitioning

This approach splits data in a large database into smaller chunks called partitions. It can improve query performance by reducing the amount of data that needs to be scanned. Partitioning methods include range, list, hash, and key partitioning. See https://mariadb.com/kb/en/partitioning-types/

In this example, query time reduced by 97% after partitioning since the DB scans only the relevant partition.

6. Caching

The query cache stores results of SELECT queries so that if the identical query is received in future, the results can be quickly returned. This is extremely useful in high-read, low-write environments (such as most websites). It does not scale well in environments with high throughput on multi-core machines, so it is disabled by default.

7. Optimizer Hints

Optimizer hints guide the optimizer’s choices for execution plans. For example, you can force the optimizer to use a specific index or join method. This is useful when you have specific knowledge about your data that the optimizer might not be aware of.

8. Statistics

The DB collects and uses statistics about the distribution of data in tables and indexes. You can update statistics with ANALYZE TABLE to maintain query performance as data changes.

9. Limits and Offsets

Do you really need all the data in the table all at once? Using LIMIT and OFFSET in queries can reduce the number of rows that need to be processed. See also, indexed pagination.

10. Query Profiling and Diagnostics

Tools like SHOW PROFILE and the Performance Schema can provide detailed information about how resources are used during query execution. This can help investigate slow queries.

Conclusion

Optimizing queries is an ongoing process that depends on the specific application requirements. Regularly tune your database and queries as data grows and changes.