You are on page 1of 7

MySQL Worst Practices

by Jonathan Baldie

Introduction

MySQL and MariaDB are two of the most popular database engines in the world. They’re rightly
chosen for their speed potential, portability, and the fact that they’re free!

Unfortunately I keep seeing developers come up against the same problems over and over
again, and making the same mistakes over and over again.

1
You want to grow your app into a successful business, and to achieve that you’ll need one or
more of the following:

• Lots of users

• Lots of data

Either of these requires a database setup that will scale well. This guide will take you through the
most common mistakes developers make with their MySQL databases.

I hope that by reading this, you’ll know how to avoid all of these mistakes and fulfil the speed
potential of your app.

Mistake #1 - You’re Doing Indexes Wrong

By far the most common mistake I see is not creating table indexes correctly, or not using
indexes at all.

As your data grows, indexes are vital for your bigger tables. They take a huge load off your
database server, because it’s much quicker and easier to look up values.

For an example of this scenario, imagine you have a massive book in front of you. To find a
section in that book, you’ll need to flick through and look at every single paragraph until you find
the section you’re after.

That’s what it’s like for MySQL if your large table has no indexes. It’s called a ‘Full Table Scan’.

But if you had a really efficient contents section and an index, you’d know exactly where in the
table to look. Much faster and much less work involved for the same result.

You see, the way table indexing works in MySQL is that each index you make will always have
the primary key appended onto it. If you think of the page numbers in a book as its primary key,
you’ll see how this works.

It’s like this: Contents -> Chapter -> Page.

In MySQL it’s the same: Index -> Primary key -> Record(s).

2
SQL Sage’s Top Tip: Write your indexes for your most common SELECT
queries

In MySQL, any time you write a query like this:

SELECT * FROM table WHERE column = 'value'

MySQL will attempt to find an index on column, because you’re doing a direct lookup on that
column.

So look in your code for your most common SQL queries, and write your indexes for them
based on the WHERE clauses.

Mistake #2 - You’re Not Using Composite Indexes

Did you know you can create indexes on multiple columns in MySQL? It can greatly improve the
speed of your more complicated queries.

The order of the columns in the index matters, though. You can’t just add them in any random
order.

The most common misconception I hear is that MySQL uses ‘filtering’ when it comes to WHERE
clauses and indexing. Totally wrong!

MySQL uses the BTREE algorithm with indexes. That means that any columns with WHERE
column = ... with direct equality will be prioritised. That is VERY important, don’t forget it.
MySQL will not know to ‘hop’ to the middle of your index.

‘Range’ lookups are anywhere you have a >, <, or BETWEEN in your WHERE clauses. They can be
added next. But you can only add one of them.

Columns in GROUP BY and ORDER BY may also be added next, but NOT if you already have a
range lookup in your query.

3
SQL Sage’s Top Tip: Use the composite index algorithm

Here’s the algorithm for writing the perfect composite index for your multi-column SELECT query:

1. Add all columns, in any order, where you use WHERE column = ... with direct equality.

2. Add column(s) from the ONLY the first condition below that your query satisfies:

a. A column in a range lookup with >, <, or BETWEEN

b. All columns in a GROUP BY list, but only if they’re in the same ASC or DESC order.

c. All columns in a ORDER BY list, but only if they’re in the same ASC or DESC order.

Mistake #3 - You’re Wrapping WHERE Clauses Inside Functions

Any time you wrap a WHERE clause inside a function, MySQL will never use indexes on that
column. It will always do a full table scan.

Examples:

• SELECT * FROM table WHERE HEX(some_column) = 'fffaaa'

• SELECT * FROM table WHERE ROUND(latitude) BETWEEN 50 AND 52

The ONLY exceptions are the in-built DATE helpers and the geo-functions like ST_WITHIN, but
they are beyond the scope of this report.

SQL Sage’s Top Tip: Structure your data so that you don’t use
functions in WHERE clauses

The solution is to structure your data in the way you actually want to deliver it and use it. If you
need all your latitudes and longitudes as integers, store them that way! Don’t multiply by
100,000 everywhere!

4
Mistake #4 - You’re Overusing Wildcard Lookups

Look, MySQL can be used as a text search engine, but that’s not its optimal use. Learn how to
use Elasticsearch instead - that’s the right tool for the job and it’s also free.

I’m talking about queries with WHERE column LIKE '%search%'.

These are okay on small tables, but they will NOT use indexes if you put the % at the beginning
of the search term. That’s just how MySQL wildcard lookups work.

SQL Sage’s Top Tip: Use wildcard lookups sparingly and don’t put the
wildcard at the beginning of the search term

If you must use wildcard lookups, only put the wildcard selector at the end, that way it’ll use any
index you have on that table.

Mistake #5 - You’re Writing Redundant Indexes

I’m a nerd for MySQL performance, but believe me it’s actually possible to go overboard with
your indexing.

If you have an index (column_1, column_2), then any query on just column_1 alone will use that
index! Aren’t composite indexes awesome.

That means that a column on just column_1 will be completely redundant. It’s not necessary,
drop it.

Side note: you will need a separate index on column_2 though - MySQL will not be able to jump
onto the second column of the first index.

5
SQL Sage’s Top Tip: Don’t make too many indexes! ‘Too many’ is
nearly as bad as ‘not enough’!

Indexes have the potential to double the size of your data, if not more. Also remember that every
time your data changes, MySQL has to rebuild the index associated with that table.

All of this combined eats up precious space, memory, and server resources in general.

Keep it cool and remember that ‘too many’ is nearly as bad as ‘not enough’!

Thank You For Reading!

Thanks once again for downloading this free book. I genuinely love writing about MySQL
performance and want to help your database-backed app be as fast as it should be!

What’s Next?

We’ve only barely scratched the surface with MySQL performance.

There’s so much more that I’m going to cover in further books. There’s partitioning, server setup,
and master-slave replication.

On my SQL Sage newsletter I’ll send you all of these books for free.

If you’ve only just joined the newsletter, email me and I’ll send you any of these you want.

If you have any questions about MySQL, any problems with your app, or if you just fancy a chat,
you can get in touch with me at jon@sqlsage.com

Legal Stuff

SQL Sage™ is a trademark of Subject Zero Ltd, a company registered in England & Wales.

6
MySQL is a trademark of Oracle Corporation, and MariaDB is a trademark of the MariaDB
Foundation.

You might also like