The more I go through others SQL, there are some common mistakes that I see developers making over and over again, so I thought why not start a series of tips that can help developers optimize their queries and avoid common pitfalls.

So this post is a part of that series of tips, and this is the first tip to start things off!

Avoid using a wild card character at the start of a LIKE pattern

There are many times I have seen SQL containing the following:

SELECT * FROM tbl WHERE col1 LIKE '%x%';

This is something that should be avoided because MySQL would not use an index for such a query.

Here is a relevant quote from MySQL Internals Manual:
“The optimizer will use an index (range search) for
column1 LIKE ’x%’
but not for
column1 LIKE ’%x’
That is, there is no range search if the first character in the pattern is a wildcard.”

Let’s test this out using some sample data.

/*Table structure for table `scores` */

CREATE TABLE `scores` (
  `id` int(11) NOT NULL DEFAULT '0',
  `name` varchar(255) DEFAULT NULL,
  `score` int(3) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `student_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

/*Data for the table `scores` */

insert  into `scores`(`id`,`name`,`score`) values (1,'ovais',99),(2,'umair',100),(3,'hassan',78),(4,'saleem',66),(5,'zeeshan',32);

Query with the first character as a wild card character

mysql> explain select * from scores where `name` like '%o%';
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table  | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | scores | ALL  | NULL          | NULL | NULL    | NULL |    5 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

Query with the first character as a non-wild card character

mysql> explain select * from scores where `name` like 'o%';
+----+-------------+--------+-------+---------------+--------------+---------+------+------+-------------+
| id | select_type | table  | type  | possible_keys | key          | key_len | ref  | rows | Extra       |
+----+-------------+--------+-------+---------------+--------------+---------+------+------+-------------+
|  1 | SIMPLE      | scores | range | student_name  | student_name | 258     | NULL |    1 | Using where |
+----+-------------+--------+-------+---------------+--------------+---------+------+------+-------------+
1 row in set (0.00 sec)

Conclusion

Take a look at the explain output of the first query, especially the type column that says 'ALL', what that means that the index on the name column student_name cannot be used, instead MySQL does a “sequential scan of table” commonly referred to as table scan which is a very costly operation.

Now take a look at the explain output of the second query, its much better than the first one, the type column now says 'range', which means MySQL would do a range scan on the key ‘student_name’ for all names starting with ‘o’.