keepcalculator

06 Numbers and Powers

MySQL Performance Optimization: Step-by-Step Guide

Card No. 06·52086 · Updated · Standard formula, shown below

This guide walks you through practical steps to optimize a MySQL database for better performance, covering indexing, query tuning, configuration, and schema design. You’ll learn how to identify bottlenecks and apply targeted fixes that reduce response times and server load.

What You’ll Need

  • Access to the MySQL server (root or a user with SUPER and PROCESS privileges).
  • MySQL client or a tool like phpMyAdmin or MySQL Workbench.
  • Basic knowledge of SQL queries and database schema.
  • Optional: a staging environment to test changes safely.

Step-by-Step

  1. Identify slow queries. Enable the slow query log by setting slow_query_log = 1 and long_query_time = 2 in your MySQL config (or via SET GLOBAL). Run the server for a few hours or days, then analyze the log to find queries that take over 2 seconds.
  2. Use EXPLAIN to analyze problematic queries. Prefix a slow query with EXPLAIN to see the execution plan. Look for type values like ALL (full table scan) or index (full index scan) and note the rows column – a high value indicates many rows examined.
  3. Add appropriate indexes. For columns used in WHERE, JOIN, ORDER BY, or GROUP BY clauses, create indexes. Use composite indexes when filtering on multiple columns. For example: CREATE INDEX idx_user_status ON users (status, created_at);. Avoid over-indexing; each index slows down writes.
  4. Optimize queries. Avoid using SELECT *; select only needed columns. Use LIMIT when you only need a subset. Replace OR with UNION when possible, and avoid functions on indexed columns (e.g., WHERE YEAR(date) = 2023 defeats the index).
  5. Tune MySQL configuration. Edit your my.cnf (or my.ini on Windows). Key parameters:
    • innodb_buffer_pool_size – set to 70-80% of available RAM for InnoDB.
    • query_cache_type – consider disabling (set to 0) in MySQL 5.7+; it’s removed in 8.0+.
    • max_connections – increase if you see ‘too many connections’ errors.
    • tmp_table_size and max_heap_table_size – increase to avoid disk-based temp tables.
  6. Normalize or denormalize schema. For OLTP (transactional) workloads, keep tables normalized to reduce redundancy. For heavy read workloads, consider denormalizing (adding redundant columns) to avoid expensive joins.
  7. Archive old data. Move rarely accessed rows to separate archive tables or a different database. This shrinks the active table size, making scans and index lookups faster.
  8. Use proper data types. Choose the smallest data type that fits your data. For example, use INT instead of BIGINT for small numbers, and VARCHAR(255) only when needed. This reduces storage and improves cache efficiency.
  9. Monitor and adjust. Use SHOW STATUS to check key metrics like Innodb_buffer_pool_read_requests vs Innodb_buffer_pool_reads (cache hit ratio). Also check Threads_connected and Slow_queries after changes.
  10. Consider partitioning. For very large tables, partition by range (e.g., by date) to limit the data scanned for queries that filter on that column. Use ALTER TABLE ... PARTITION BY RANGE (YEAR(created_at)).

Common Mistakes

  • Over-indexing: Adding too many indexes slows down INSERT/UPDATE/DELETE and increases storage.
  • Ignoring the slow query log: Guessing which queries are slow instead of measuring.
  • Using functions on indexed columns: This prevents index usage, forcing full scans.
  • Setting buffer pool too large: If it exceeds physical RAM, the system swaps, crashing performance.
  • Not testing on a staging environment: Applying changes directly to production can cause downtime.

Tips

  • Start with the most frequent slow queries; a 10x improvement on one query is better than 1% on many.
  • Use EXPLAIN ANALYZE (MySQL 8.0+) to get actual execution time per step.
  • Regularly run OPTIMIZE TABLE on tables with frequent deletes to reclaim space and improve I/O.
  • Use a connection pooler (like ProxySQL) to reduce connection overhead.
  • Keep statistics updated by running ANALYZE TABLE after major data changes.

Troubleshooting

Queries still slow after adding indexes? Check if the index is actually used with EXPLAIN. If not, the query might have a LIKE '%...' pattern or a function on the column. Rewrite the query or use a generated column with an index.

Server crashes after changing buffer pool size? Reduce the value; you may have over-allocated memory. Check free -h to see available RAM.

MySQL won’t start after config changes? Check error logs (/var/log/mysql/error.log) for syntax errors in my.cnf. Revert to the previous config and restart.

Replication lag increases? If you have replicas, optimization on the master might not propagate. Check replica threads and consider using row-based replication.

Frequently Asked Questions

Q: How do I know if my database needs optimization?
A: Monitor slow query log, CPU usage, and response times. If queries take >1 second or CPU is consistently high, it’s time to optimize.

Q: What is the most impactful optimization?
A: Adding proper indexes is usually the biggest win, especially for SELECT queries on large tables.

Q: Should I use InnoDB or MyISAM?
A: InnoDB is recommended for most use cases due to transactions, foreign keys, and better crash recovery. MyISAM is only for legacy systems.

Q: How often should I run OPTIMIZE TABLE?
A: Only when you have significant fragmentation (e.g., after mass deletes). Running it frequently on large tables can cause downtime.

Q: Can I optimize without restarting MySQL?
A: Yes, many settings like innodb_buffer_pool_size can be changed dynamically via SET GLOBAL, but some require a restart.

Q: What is the best way to monitor performance?
A: Use MySQL Performance Schema, SHOW STATUS, and tools like Percona Monitoring and Management (PMM) or MySQL Enterprise Monitor.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →