This is an example of "High Performance MySQL 3rd".
mysql> EXPLAIN SELECT * FROM products WHERE actor='SEAN CARREY' AND title like '%APOLLO%';
The book said that MySQL can't perform the LIKE as below.
MySQL can’t perform the LIKE operation in the index. This is a limitation of the low-level storage engine API, which in MySQL 5.5 and earlier allows only simple comparisons (such as equality, inequality, and greater-than) in index operations. MySQL can perform prefix-match LIKE patterns in the index because it can convert them to simple comparisons, but the leading wildcard in the query makes it impossible for the storage engine to evaluate the match. Thus, the MySQL server itself will have to fetch and match on the row’s values, not the index’s values.
After that, the book gave a "deferred join" improvement.
mysql> EXPLAIN SELECT * FROM products
-> JOIN (
-> SELECT prod_id FROM products WHERE actor='SEAN CARREY' AND title LIKE '%APOLLO%'
-> ) AS t1 ON (t1.prod_id=products.prod_id);
Even the (actor, title, prod_id) is a "covering index", MySQL can't also perform the LIKE in the index.
I am so confused!
This is an optimization that works around technical limitations about how MySQL works, and less about logic. Especially your understanding that you cannot use an index to directly find matches for a leading wildcard is correct.
The main problem is that a covering index in MySQL 5.5 technically didn't exactly do what you assume it does (and could do).
To read the quoted statement from the book properly, you have to know that there is a difference between The MySQL server and the underlying storage engine. The MySQL server takes your query, decides how to execute it, sends a request to the (InnoDB) storage engine via an api, and gets back some rows.
So for your first query, MySQL asks InnoDB to give it the following data: all columns (
select *), using an index to look foractor='SEAN CARREY'. Although it would be nice and you assume that a covering index would do this, unfortunately, it cannot also directly eliminate rows based ontitle like '%APOLLO%', becauseSince you asked for
*, it retrieves all columns, which requires to look into the table data, for all rows with the correct actor (using the index) from the InnoDB engine and then filter those afterwards, sinceIn the second query, the MySQL server only needs
prod_id(as per request) andtitle(to do thewherecomparison) from the storage engine. This is now actually covered by the index! Although the upper layer still needs to do the evaluation ontitle like '%APOLLO%', the storage engine now does not need to read the actual table data to fulfill the request for the subquery.The MySQL server can now evaluate the data it received and send another request to the storage engine to retrieve all columns for the
prod_idthat fulfill thewhere-condition. In extreme cases this might not filter at all (e.g. every row withactor='SEAN CARREY'could also fulfilltitle like '%APOLLO%'), and then the deferred join could be a bit slower, since you do more work overall.You think this is not what a covering index should do? You are right. And MySQL 5.6 learned how to do it more properly:
Since it was only needed to workaround technical issues, you do not need a defered join here anymore (although you should not forget about it, it can be useful in other situations). Your explain output for your first query should now include