MySQL
Search
SQL

MySQL Indexing Mistakes 101

intro

Let’s learn about the most frequent mistakes connected to MySQL indexing. Explore methods to supercharge your MySQL instance using indexes!

Tools used in the tutorial
Tool Description Link
Dbvisualizer DBVISUALIZER
TOP RATED DATABASE MANAGEMENT TOOL AND SQL CLIENT
mariadb MARIADB
THE MARIADB DATABASE
MySQL logo MySQL
THE MYSQL DATABASE

Query performance is at the top of the mind of every developer and one thing that has always helped improve it was indexes — developers and DBAs turned to indexes when they needed to optimize an SQL query running through billions of records or when JOIN SQL queries started going sour.

Whatever your use case is, MySQL indexing is something for everyone, but improper indexing is also home to a couple of rookie mistakes that, if not dealt with properly, can cause your database (and your application) to crash and burn in the process.

Let’s explore these mistakes and see how to avoid them!

Types of Indexes in MySQL

Unfortunately, in many cases, the documentation of MySQL isn’t very clear when it comes to indexing. Sometimes, to get the gist of what’s happening within the documentation, you have to be educated about what the internals of your database contains and how indexing works in the first place.

For those who know their way around index types in MySQL, documentation is an awesome place, however, those who don’t may find things a little harder to come by.

MySQL has the following index types:

  1. B-Tree (Balanced Tree) indexes — These are the “vanilla” index type in MySQL. B-Tree indexes help your database quickly find data by acting as pointers to it, but they don’t do anything that impressive beyond that.
  2. Hash indexes — Used exclusively by the MEMORY storage engine within MySQL and allow for exact matches, but not for anything else (queries searching with the “<=>” or “=” operators will be blazing fast, while the index won’t provide much support for anything else.)
  3. Spatial indexes — Used to index geographic, or spatial, data, hence the name.
  4. Partial or prefix indexes — They cover a prefix of a column, hence the name.
  5. Multicolumn or composite indexes — They cover multiple columns at the same time and are exceptionally useful in cases where we read data from the index instead of reading it from the disk.
  6. Covering indexes — These kinds of indexes “cover” all columns required by an SQL query, hence the name.
  7. Clustered indexes — Also known as “primary keys” indexes because a table can only have one clustered index that is commonly defined as a primary key, and all indexes that are not part of the clustered index are considered to be secondary indexes. Find out more in our article on MySQL primary keys.

Aside from index types, one other common cause of concern is deciding when and what data to index. That’s not rocket science for many experienced DBAs, but decisions like that can indeed drown many developers in the woods, so we’ll get into that too.

What and When to Apply MySQL Indexing?

The best way to assess what data should be indexed is to look at what data your queries are accessing in the first place. Inspect your queries — if you see a SELECT query with a demo column after the WHERE clause, add an index on it, run it through an EXPLAIN clause (examples below) and see how your database uses it. That’s the key to MySQL indexing.

Aside from deciding what to index, another important question is when to index in the first place for your queries to obtain (and maintain) maximum performance for your use case. Consider indexing your data when:

  • You have millions or even billions of records to work with
  • You’ve tried partitioning, but that just didn’t help
  • You run a big data-based search engine (that goes hand in hand with the first point)
  • Your database is optimized and databases are normalized, but SQL queries reading data still run slowly or grind to a halt

Index your data once your database starts to show the first signs of discontent in relation to the points above — or when you have a gut feeling to index a column or two. That works too.

Most Common MySQL Indexing Mistakes

Before you index your data, be aware of MySQL indexing mistakes — these mistakes won’t “eat” your data, database, or anything connected to them, but they can certainly cause the performance of queries acting on your data to dive into the ground. The worst indexing mistakes you can do to your database are as follows:

  1. Indexing when you don’t have enough data — Since indexes in your database act as indexes in a book, indexing only makes sense when you have enough data to necessitate work for the database. That means that you should only consider indexing if the use case of your application necessitates sifting through a lot of data in a SELECT query.
  2. Indexing without being aware of the consequences for other queries — All indexes will slow down INSERT, UPDATE, and DELETE queries because with an index, your database has to insert, update or delete the data in the index as well as act on the data itself.
  3. Indexing every column after the WHERE clause — Another common mistake is related to developers indexing every column after the WHERE clause. Such mistakes can be very costly if we have a lot of data and index everything, but our index doesn’t even help our use case! Talk about wasting storage space for no reason…
  4. Indexing without consulting with your database and your use case — When deciding to index anything, “ask” your database whether your use case necessitates indexing in the first place and if yes, what kind of indexes you should be using. You can easily do that by employing an EXPLAIN clause (example below.)
  5. Not understanding what kind of index to use — Understanding the intricacies of indexes in MySQL is vital for making a good choice in regards to them. If you run a big data-based data breach search engine, it may be a way better idea to “cover” all of the columns your app is using to execute the query instead of covering the first column after the WHERE clause with an index. Do that and you will enable MySQL to read the data from the index instead of reading it from the disk, and thus, your search queries will be so much faster!
  6. Indexing without making use of partitions (sometimes) — What if you’ve indexed and you notice that indexes don’t help your use case that much? I mean, what if you have 10,000,000,000 rows for your database to sift through, you’re using the covering index, and your queries are still rather slow? What do you do? The answer is obvious — you need to further reduce the amount of data accessed by your database — and partitioning is a great way to do just that!

Another mistake has to do with things developers do before building indexes. This is where MySQL indexing comes into place — an index for your use case is easy to create if you:

  1. Understand what type of index your use case necessitates — As not all indexes are the same, understanding what certain types of indexes do before employing them is a wise decision.
  2. Your database is properly configured, normalized and, if necessary, partitioned — Indexes can only do so much and they’re not the holy grail. We’d advise you to turn to mysql indexing only when you’ve fiddled with the my.cnf file, normalized your databases if necessary, and applied a partition or two if your use case necessitates that (read: if you have more than 100M rows you’re working with.)

See how both of those points connect with what we’ve said above? To properly avoid making mistakes in the indexing realm, you have to understand how your database thinks when working with indexes, too. And that’s where the SQL EXPLAIN clause comes into play.

Utilizing the EXPLAIN Clause for Indexes

To unleash the full power of the EXPLAIN clause for MySQL indexing, we first have to understand what we’re working with in the first place. For that, SHOW INDEXES FROM [table_name] will help (make sure to select the database you’re running the query on before executing it too):

Indexes Existing in a Table
Indexes Existing in a Table

Alright, we’re lying — that’s the ghetto way of doing things. Flick back to DbVisualizer — the database client with the highest user satisfaction in the market — then select your database, the table you’re working with, and you will be able to observe all of the indexes existing on this table in a much nicer fashion:

DbVisualizer displaying the defined indexes
DbVisualizer displaying the defined indexes

Once you understand what indexes exist on a table, craft a query that you would use to assist your use case (make sure to have a column or two after the WHERE clause to ensure that the query is using indexes.) Once your query is ready, add an EXPLAIN clause in front of it so it looks like so:

Copy
        
1 EXPLAIN SELECT * FROM `demo_table` 2 WHERE `username` = 'Demonstration' AND `email` LIKE 'sample%';
EXPLAINing a Query in DbVisualizer
EXPLAINing a Query in DbVisualizer

Then, observe the output of the EXPLAIN clause. It should return the following:

  1. select_type — Whether the SELECT query has used a join or was executed in a “SIMPLE” fashion instead, hence the value.
  2. table — The table the SELECT query has executed on.
  3. type — The type of the JOIN, if any.
  4. possible_keys — The possible indexes (keys are synonyms) to indexes MySQL could use.
  5. key — The key (index) MySQL actually used. (null) means that no index was used.
  6. key_len — The length of the index. If no index is used, no length will be displayed.
  7. ref — The columns that were compared to the index.
  8. rows — The number of rows in a table.
  9. Extra — Provides any extra information relevant to the query (e.g. Using where means that the SQL query has used a WHERE clause when executing, etc.)

For the purposes of this blog, when avoiding MySQL index mistakes, you’d be mostly interested in the values under the possible_keys, key, and key_len columns: these columns define what kind of index was considered for use by your database (possible_keys), what index was used by your query, if any (that’s the key column), and what’s the length of the index (key_len).

Provided our demo_table has a primary index on id , a descending index on username, and a partial index on email, these types of indexes could be used when:

We’re making use of the username column after the WHERE clause (query #1):

The `username` column after the `WHERE` clause
The `username` column after the `WHERE` clause

We’re looking for infomation on rows bearing a specific ID (query #2):

Looking for infomation on a specific ID
Looking for infomation on a specific ID

Or we’re looking for information pertaining to email addresses. Here’s where index cardinality comes into play as well — if our index cardinality (the amount of unique values within the index) is rather low, our database may not be able to use the index in the first place:

Index cardinality in DbVisualizer
Index cardinality in DbVisualizer
The Index Not Being Considered for Use
The Index Not Being Considered for Use

All this means that we have another thing to worry about after creating our index: we have to ensure that the amount of unique values in the index is high enough to necessitate our database looking through them.

There are other things at play, too, however, we’ll leave those for you to figure out. With that being said, there are resources that can help you with this, and the book “Hacking MySQL: Breaking, Optimizing, and Securing MySQL for Your Use Case” is one of them.

The book focuses on how developers “break” their databases to necessitate optimization in the first place, and how to secure it after you optimize your database too, so it will bring a refreshing standpoint to the way you look at your databases.

Summary

This blog has walked you through a bunch of indexing mistakes on MySQL, with the most important of those being related to understanding index types, ensuring you have enough data to necessitate indexing in the first place, and consulting with the EXPLAIN clause. Perform those actions and your database will surely thank you — and if it doesn’t, read a book or two to ensure that it will.

FAQ

What index should I choose when working with MySQL?

The most frequent type of index in MySQL is the B-Tree index, however, there are other types, so to make a decision, evaluate the use cases they assist with carefully and make a wise decision based on your use case, the problems you face, and your experience dealing with MySQL-specific issues.

How many indexes should a single table have?

That depends on your use case. Don’t overdo things — if you index every column in a table, you’re probably doing it wrong and should look into storage engines that do it for you instead — but if you understand how indexes work after consulting the EXPLAIN clause, the solution should present itself to you pretty soon. To learn specific things like these, we recommend digging into books specializing in these topics.

Are there other ways than MySQL indexing to optimize queries?

There sure are — while we won’t be able to list every optimization technique in a single answer, consider partitioning your tables if your use case necessitates that, normalize your database, and only select data that you need to keeping in mind that queries are tasks composed of other tasks. That should be a good starting point. MySQL indexing is not the only solution!

Dbvis download link img
About the author
LukasVileikisPhoto
Lukas Vileikis
Lukas Vileikis is an ethical hacker and a frequent conference speaker. He runs one of the biggest & fastest data breach search engines in the world - BreachDirectory.com, frequently speaks at conferences and blogs in multiple places including his blog over at lukasvileikis.com.
The Table Icon
Sign up to receive The Table's roundup
More from the table
Title Author Tags Length Published
title

A Complete Guide to the Different Types of DBMS

author Antonello Zanini tags DBMS NOSQL SQL 8 min 2025-03-31
title

SQL TRUNCATE TABLE: A Complete Guide

author Antonello Zanini tags MySQL ORACLE POSTGRESQL SQL SQL SERVER 6 min 2025-03-26
title

A Complete Guide to SQL Window Functions

author Lukas Vileikis tags DATA TYPES DbVisualizer MySQL SQL 5 min 2025-03-25
title

A Complete Guide to the FULL OUTER JOIN SQL Operation

author Antonello Zanini tags MySQL ORACLE POSTGRESQL SQL SQL SERVER 7 min 2025-03-24
title

How to Use JOIN in a DELETE Query in SQL

author Antonello Zanini tags MySQL ORACLE POSTGRESQL SQL SQL SERVER 8 min 2025-03-20
title

What Is the MySQL DSN Format for Golang?

author Lukas Vileikis tags DbVisualizer MySQL SQL 4 min 2025-03-19
title

Operations Across Entire Columns: SQL Aggregate Functions Explained

author Lukas Vileikis tags DbVisualizer MySQL SQL Transaction 8 min 2025-03-18
title

A Guide to the SQL CREATE TABLE Statement

author Antonello Zanini tags MySQL ORACLE POSTGRESQL SQL SQL SERVER 7 min 2025-03-17
title

Clustered Indexes in PostgreSQL: What They Are and How to Use Them

author Lukas Vileikis tags DbVisualizer POSTGRESQL SQL 5 min 2025-03-13
title

How to Deal With a Swollen SQL Transaction Log

author Antonello Zanini tags SQL SQL SERVER 7 min 2025-03-12

The content provided on dbvis.com/thetable, including but not limited to code and examples, is intended for educational and informational purposes only. We do not make any warranties or representations of any kind. Read more here.