MySQL indices and order - mysql

This is a question that I've had forever.
As far as I know the order of indices matter. So an index like [first_name, last_name] is not the same as [last_name, first_name], right?
If I only define the first index, does it mean that it will only used for
SELECT * FROM table WHERE first_name="john" AND last_name="doe";
and not for
SELECT * FROM table WHERE last_name="doe" AND first_name="john";
Since I am using a ORM, I have no idea in which order these columns are going to be called. Does that mean that I have to add indices on all permutations? That is doable if I have a 2 column index, but what happens if my index is on 3 or 4 columns?

Index order matters when your query conditions only apply to PART of the index. Consider:
SELECT * FROM table WHERE first_name="john" AND last_name="doe"
SELECT * FROM table WHERE first_name="john"
SELECT * FROM table WHERE last_name="doe"
If your index is (first_name, last_name) queries 1 and 2 will use it, query #3 won't.
If your index is (last_name, first_name) queries 1 and 3 will use it, query #2 won't. Changing the condition order within WHERE clause has no effect in either case.
Details are here
Update:
In case the above is not clear - MySQL can only use an index if the columns in query conditions form a leftmost prefix of the index. Query #2 above can not use (last_name, first_name) index because it's only based on first_name and first_name is NOT the leftmost prefix of the (last_name, first_name) index.
The order of conditions WITHIN the query does not matter; query #1 above will be able to use (last_name, first_name) index just fine because its conditions are first_name and last_name and, taken together, they DO form a leftmost prefix of (last_name, first_name) index.

ChssPly76 is correct that the order of boolean expressions does not have to match the order of columns in the index. Boolean operators are commutative, and the MySQL optimizer is smart enough to know how to match the expression to the index in most cases.
I also want to add that you should learn how to use the EXPLAIN feature of MySQL so you can see for yourself which indexes the optimizer will choose for a given query.

Why not to extend the answer a little bit to make completely everything crystal clear at once.
If the table has a multiple-column index, any leftmost prefix of the index can be used by the optimizer to find rows. For example, if you have a three-column index on (col1, col2, col3), you have indexed search capabilities on (col1), (col1, col2), and (col1, col2, col3).
MySQL cannot use an index if the columns do not form a leftmost prefix of the index. Suppose that you have the SELECT statements shown here:
SELECT * FROM tbl_name WHERE col1=val1;
SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
SELECT * FROM tbl_name WHERE col2=val2;
SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;
If an index exists on (col1, col2, col3), only the first two queries use the index. The third and fourth queries do involve indexed columns, but (col2) and (col2, col3) are not leftmost prefixes of (col1, col2, col3). - MySQL dev

Related

Clarification of MySQL index required to be "spanning" of all "and groups"

From the MySQL documentation here
Any index that does not span all AND levels in the WHERE clause is not used to optimize the query. In other words, to be able to use an index, a prefix of the index must be used in every AND group.
What exactly does this mean? Does it mean that for an index to be used, that every component of the AND query must refer to that index?
So lets say we have a Person table with SID (primary), first_name (index), last_name.
Does that mean that for the following query
Select * from Person where first_name='foo' and last_name='bar'
will not use the index on first_name?
An AND group is a set of comparisons that are combined with AND. A WHERE clause has multiple AND groups if it uses OR to combine several of these, e.g.
WHERE (col1 = 1 AND col2 = 2 AND col6 = 10) OR (col1 = '5' AND col4 = 'B' AND col2 = 16)
has two AND groups. There's one group that tests col1, col2, and col6, and another group that tests col1, col4, and col2.
So an index can be used if it has a prefix that's tested in every one of these groups. For instance, an index on (col1, col2, col3) could be used because the prefix (col1, col2) spans both groups.
That statement in the document is rather misleading. It seems to contradict directly with the first example given under that statement.
The following WHERE clauses use indexes:
... WHERE index_part1=1 AND index_part2=2 AND other_column=3
Here it's clearly stated that the index is used even though other_column is not a part of the index. The confusion then, is caused by what exactly is an 'AND Group'. Bamar has explained that really well in his answer so I will not go into that here. But suffice to say
Select * from Person where first_name='foo' and last_name='bar'
Will user an index provided that number of rows with first_name = 'foo' is much smaller than total number of rows in the table.
The statement you quoted here is referring to the multiple column indexing or compound indexes.
It indicates that if you have created an index on multiple columns, they all should be presented in the same order in and groups.
If you have crested an index on col1, col2, col3
And groups can be
col1=1 and col2=2 and col3=3
You can also have
col1=1 and col2=2
But you cannot have
col2=1 and col3=3
Because it is not the prefix of the index

SQL query the last created item performance

I am trying to fetch the last created item in a large table like this:
SELECT `raw_detection`.* FROM `raw_detection`
WHERE `raw_detection`.`duplicated` = 0
AND `raw_detection`.`audio_source_id` = 100
ORDER BY created_at desc LIMIT 1
But this query takes a long time to run (more than 2 seconds).
I have this index:
KEY `index_raw_detections_audio_source`(`audio_source_id`,`duplicated`,`created_at`)
Is there any better way to fetch the last created item for a specific audio source?
Your key references three columns. It cannot be used to speed up queries using only the created_at portion of the key. Try creating an additional key for just created_at.
For reference, from the MySQL doc:
If the table has a multiple-column index, any leftmost prefix of the index can be used by the optimizer to look up rows. For example, if you have a three-column index on (col1, col2, col3), you have indexed search capabilities on
(col1), (col1, col2), and (col1, col2, col3).
MySQL cannot use the index to perform lookups if the columns do not form a leftmost prefix of the index.
https://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html
In your select, specify the columns needed rather than doing select *

Unique first column in multi-column index

I have multi-column index for 2 columns. Can I make first column unique without making separate index for that?
If I understand correctly mysql can use only first column in this index for lookups, so can it use it to detect uniqueness?
The short answer is "No". Because it doesn't make much sense.
Indeed, MySQL is able to use a multiple-column index for operations that use only the leftmost "n" columns from the index definition.
Let's say you have an index on columns (col1, col2). MySQL can use it to find records matching conditions on both col1 and col2, GROUP BY col1, col2 or ORDER BY col1, col2. It is important to notice that col1 and col2 needs to used in this order in the GROUP BY or ORDER BY clause. Their order doesn't matter on WHERE or ON clauses as long as both are used.
MySQL can also use the same index for WHERE or ON conditions and GROUP BY or ORDER BY clauses that contain only col1. It cannot, however, use the index if col2 appears without col1.
What happens when you have an index on columns (col1, col2) and all the rows have distinct values in column col1?
Let's assume we have a table that have distinct values in column col1 and it has an index on columns (col1, col2). When MySQL needs to find the rows that match WHERE col1 = val1 AND col2 = val2, by consulting the index it can find the row that have col1 = val1. It doesn't need to use the index to refine the list of candidate rows because there is no list: there is at most one row having col1 = val1.
Sure, most of the times MySQL will use the index to check if col2 = val2 but having col2 in this index doesn't bring more useful information to the index. The storage space it takes and the processing power it uses on table data updates are too big for the tiny contribution it adds to rows searching.
The whole purpose of having indexes on multiple columns is to help searching by shrinking the list of matching rows for a given set of values when the columns included in a multiple-column index cannot be used individually because they don't contain enough distinct values.
Technically speaking, there is no way to tell MySQL you want to have a multiple-column index on (col1, col2) that must have unique values on col1. Create an UNIQUE INDEX on col1 instead. Then think about the data you have in the table and the queries you run against it and decide if another index on col2 only isn't better than the multiple-column index on (col1, col2).
In order to decide you can create the new indexes (UNIQUE on col1, INDEX on col2), put EXPLAIN in front of the most frequent queries you run on the table and check what index will pick MySQL up for use.
You need to have enough data (thousands of rows, at least, more is better) in the table to get accurate results.
You asked.
I have multi-column index for 2 columns. Can I make first column unique without making separate index for that?
The answer is no. You need a separate unique index on the first column to enforce a uniqueness constraint.

Do MySQL complex indexes involve simple indexes?

If I set a multi-column index -unique for example- with columns (A, B) and search by A or B independently, will they be as fast as if I also have simple indexes in A and B?
Are those extra simple indexes necessary?
From MYSQL:MySQl 5 Reference
If the table has a multiple-column index, any leftmost prefix of the index can be used by the optimizer to find rows. For example, if you have a three-column index on (col1, col2, col3), you have indexed search capabilities on (col1), (col1, col2), and (col1, col2, col3).
MySQL cannot use an index if the columns do not form a leftmost prefix of the index. Suppose that you have the SELECT statements shown here:
SELECT * FROM tbl_name WHERE col1=val1;
SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
SELECT * FROM tbl_name WHERE col2=val2;
SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3;
If an index exists on (col1, col2, col3), only the first two queries use the index. The third and fourth queries do involve indexed columns, but (col2) and (col2, col3) are not leftmost prefixes of (col1, col2, col3).
If you create any index that is (A,B), MySQL can utilize that index for queries and sorts that have just A, or A then B. It can not use it for "B". The basic idea is that any prefix of the index is useful.
You don't have to create a separate one for "A", but you would need one for "B" if B was going to be sorted on or used in a where clause without "A".

Mysql effective indexes

Currently I am creating indexes as I need them for a particular sql query.
But they are starting to overlap each other.
Is there any rule to define them effectively?
For example:
If I have two indexes for column1 and column2, does the composite index by column1, column2 improve select by both columns?
What is there any difference between an index by column1 and column2 over index by column2 and column1?
Q: If I have two indexes for column1 and column2, does the composite index by column1, column2 improve select by both columns?
Yes then composite Index is better.
From Mysql
"mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
If a multiple-column index exists on col1 and col2, the appropriate rows can be fetched directly. If separate single-column indexes exist on col1 and col2, the optimizer attempts to use the Index Merge optimization (see Section 8.3.1.4, “Index Merge Optimization”), or attempts to find the most restrictive index by deciding which index excludes more rows and using that index to fetch the rows."
Q: What is there any difference between an index by column1 and column2 over index by column2 and column1?
Yes it will make difference. It depends on how you form your query.
From the Mysql docs:
Example If you have index like below on table :
INDEX name (last_name,first_name)
"The name index is an index over the last_name and first_name columns. The index can be used for lookups in queries that specify values in a known range for combinations of last_name and first_name values. It can also be used for queries that specify just a last_name value because that column is a leftmost prefix of the index."
You will get advantage of index for below query:
SELECT * FROM test WHERE last_name='Widenius';
But index is not used for lookups in the following queries:
SELECT * FROM test WHERE first_name='Michael';
Hope this will help !!
An index over two columns A and B is working as an index for column A also, but not as an index for column B.
I don't know if there is an simple rule for indexes, maybe just look for the columns involved in where clauses and order by statements in your queries and evaluate which to use.
Keep in mind that an index makes sense for a large number of rows where you search for a small subset. Indexes also slow down insertion and updates, so use them wisely. It is often enough to simply index all rows that are used to JOIN and add further ones if you run into performance issues.
If I have two indexes for column1 and column2, does the composite index by column1, column2 improve select by both columns?
Yes, it does. Separate indexes have to get merged first or just one index is used.
What is there any difference between an index by column1 and column2 over index by column2 and column1?
In a compound index the order of the columns matters, yes. If your query has only column2 in the WHERE clause, a compound index over (column1, column2) will not be used.
If you have a compound index over (column1, column2) it can also be used if your query only has column1 in WHERE clause.
For additional information see other answers I gave to questions about indexing:
MYSQL Long super-keys
MySQL query optimization of LIKE term% ORDER BY int
Q)If I have two indexes for column1 (A) and column2 (B), does the composite index by column1, column2 improve select by both columns?
yes if you have a just two indices A and B, SELECT something from table where A = 1 and B =2 will be using just one of two indices, but if you have compound index A,B it will use it, which should be faster
Q) What is there any difference between an index by column1 and column2 over index by column2 and column1?
sequence do matters in compound indices. Suppose you have the same query as above, and your table is 1 mln entries and only 50 of them match A=1 and 10000 match B=1, than compound index A,B will perform much better than B,A. So you need to choose first element of the index with the smallest cardinality.
This might be usefull
http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html
http://stackoverflow.com/questions/1823685/when-should-i-use-a-composite-index