I have query that uses order-by group-by
select count(*),filed2
from table1 where field1>x group by filed2 order by count(*) desc
what are the best indexes for this query.
sholud I index filed1,field2 seprate or together?
You should create the index with both columns in two different orders
ALTER TABLE table1 ADD INDEX field1_field2_ndx (field1,field2);
ALTER TABLE table1 ADD INDEX field2_field1_ndx (field2,field1);
You should not create individual indexes because making the index with both columns will cause the query to pass through the index only to satisfy the query. It would never need to touch the table.
Even if you made individual indexes, the Query Optimizer would choose the two column index anyway.
Now that you have the two indexes, just trust the Query Optimizer to select the correct index. Based on the query, the EXPLAIN plan would choose the field2_field1_ndx index.
Related
I have a table in MySQL with two columns
id int(11) unsigned NOT NULL AUTO_INCREMENT,
B varchar(191) CHARACTER SET utf8mb4 DEFAULT NULL,
The id being the PK.
I need to do a lookup in a query using either one of these. id in (:idList) or B in (:bList)
Would this query perform better if, there is a composite index with these two columns in them?
No, it will not.
Indexes can be used to look up values from the leftmost columns in an index:
MySQL can use multiple-column indexes for queries that test all the columns in the index, or queries that test just the first column, the first two columns, the first three columns, and so on. If you specify the columns in the right order in the index definition, a single composite index can speed up several kinds of queries on the same table.
So, if you have a composite index on id, B fields (in this order), then the index can be used to look up values based on their id, or a combination of id and B values. But cannot be used to look up values based on B only. However, in case of an or condition that's what you need to do: look up values based on B only.
If both fields in the or condition are leftmost fields in an index, then MySQL attempts to do an index merge optimisation, so you may actually be better off having separate indexes for these two fields.
Note: if you use innodb table engine, then there is no point in adding the primary key to any multi column index because innodb silently adds the PK to every index.
For OR I dont think so.
Optimizer will try to find a match in the first side, if fail will try the second side. So Individual index for each search will be better.
For AND a composite index will help.
MySQL index TIPS
Of course you can always add the index and compare the explain plan.
MySQL Explain Plan
The trick for optimizing OR is to use UNION. (At least, it works well in some cases.)
( SELECT ... FROM ... WHERE id IN (...) )
UNION DISTINCT
( SELECT ... FROM ... WHERE B IN (...) )
Notes:
Need separate indexes on id and B.
No benefit from any composite index (unless it is also "covering").
Change DISTINCT to ALL if you know that there won't be any rows found by both the id and B tests. (This avoids a de-dup pass.)
If you need ORDER BY, add it after the SQL above.
If you need LIMIT, it gets messier. (This is probably not relevant for IN, but it often is with ORDER BY.)
If the rows are 'wide' and the resultset has very few rows, it may be further beneficial to do
Something like this:
SELECT t...
FROM t
JOIN (
( SELECT id FROM t WHERE id IN (...) )
UNION DISTINCT
( SELECT id FROM t WHERE B IN (...) )
) AS u USING(id);
Notes:
This needs PRIMARY KEY(id) and INDEX(B, id). (Actually there is no diff, as Michael pointed out.)
The UNION is cheaper here because of collecting only id, not the bulky columns.
The SELECTs in the UNION are faster because you should be able to provide "covering" indexes.
ORDER BY would go at the very end.
I have a table with 500k rows. I have specific table which takes really long time to run every query.
One of the queries is:
SELECT *
FROM player_data
WHERE `user_id` = '61120'
AND `opzak` = 'ja'
ORDER BY opzak_nummer ASC
the opzak_nummer column is a tinyint with a number.
EXPLAIN:
Is there any way to improve this query performance and the general of this query/table?
The table name is player_data and includes about 25 columns, most of them are integers with values of stats.
The index is id AUTO_INCREMENT.
You need to run that query, it will alter table and add index. You can read more details here http://dev.mysql.com/doc/refman/5.7/en/drop-index.html
ALTER TABLE pokemon_speler ADD INDEX index_name (user_id, opzak);
The optimal index for that query is either of these:
INDEX(user_id, opzak, opzak_nummer)
INDEX(opzak, user_id, opzak_nummer)
The first two columns do the filtering; the last avoids a tmp table and sort by consuming the ORDER BY.
Is any combination of columns 'unique' (other than id)? If so, we might be able to make it run even faster.
I would like to know if it is necessary to create an index for all fields within a table if one of your queries will use SELECT *.
To explain, if we had a table that 10M records and we did a SELECT * query on it would the query run faster if we have created an index for all fields within the table or does MySQL handle SELECT * in a different way to SELECT first_field, a_field, last_field.
To my understanding, if I had a query that did SELECT first_field, a_field FROM table then it would bring performance benefits if we created an index on first_field, a_field but if we use SELECT * is there even a benefit from creating an index for all fields?
Performing a SELECT * FROM mytable query would have to read all the data from the table. This could, theoretically, be done from an index if you have an index on all the columns, but it would be just faster for the database to read the table itself.
If you have a where clause, having an index on (some of) the columns you have conditions on may dramatically improve the query's performance. It's a gross simplification, but what basically happens is the following:
The appropriate rows are filtered according to the where clause. It's much faster to search for these rows in an index (which is, essentially, a sorted tree) than a table (which is an unordered set of rows).
For the columns that where in the index used in the previous step the values are returned.
For the columns that aren't, the table is accessed (according to a pointer kept in the index).
indexing a mysql table for a column improves performance when there is a need to search or edit a row/record based on that column of that table.
for example, if there is an 'id' column and if it is a primary key; And in that case if you want to search a record using where clause on that 'id' column then you don't need to create index for the 'id' column because primary key column will act as an indexed column.
In another case, if there is an 'pid' column in the table and if it is not a primary key; Then in order to search based on 'pid' column then to improve performance it is better to create an index for the 'pid' column. That will make query fast to search the expected record.
I have a query SELECT.. WHERE user_id='' && date>:expire && used=0;
When I try to create index. should I create all together in one query like
CREATE INDEX new_index ON table (user_id, date, used)
or should I separate them and create index for each column?
This really depends on how you plan the query these columns. Your safest bet would be just make indexes for each column, though this may not yield optimum performance.
Multi-column indexes are useful for cases where:
You need to enforce a unique constraint across the combination of column values
You know that you will always uses columns for joins, where clauses, order by, group by, etc. in a specific combination
For example for the combo index you proposed (user_id, date, used) you would be able to utilize the index only in the following conditions:
You are doing join, where, etc. only on user_id
You are doing join, where, etc. on user_id and date
You are doing join, where, etc. on all three columns
You would not be able to utilize the index for these cases
You are doing join, where, etc. on date or used individually
You are doing join, where, etc. on date and used
For further reading, here is MySQL documentation on multi-column indexes:
http://dev.mysql.com/doc/refman/5.5/en/multiple-column-indexes.html
Based on your query, you should use a multi-column index. However, the right index is:
CREATE INDEX new_index ON table (user_id, used, date)
Note that date is last in the index, because you have an inequality.
MySQL happens to have a very good discussion here on multi-column indexes and how they are used.
I have a query that looks like the following:
select count(*) from `foo` where expires_at < now()”
since expires_at is indexed, the query hits the index no problem. however the following query:
select count(*) from `foo` where expires_at < now() and some_id != 5
the index never gets hit.
both expires_at and some_id are indexed.
is my index not properly created?
This query:
SELECT COUNT(*)
FROM foo
WHERE expires_at < NOW()
can be satisfied by the index only, without referring to the table itself. You may see it from the using index in the plan.
This query:
SELECT COUNT(*)
FROM foo
WHERE expires_at < NOW()
AND some_id <> 5
needs to look into the table to find the value of some_id.
Since the table lookup is quite an expensive thing, it is more efficient to use the table scan and filter the records.
If you had a composite index on expires_at, some_id, the query would probably use the index both for ranging on expires_at and filtering on some_id.
SQL Server even offers a feature known as included fields for this. This command
CREATE INDEX ix_foo_expires__someid ON foo (expires_at) INCLUDE (some_id)
would create an index on expires_at which would additionally store some_id in the leaf entires (without overhead of sorting).
MySQL, unfortunately, does not support it.
Probably what's happening is that for the first query, the index can be used to count the rows satisfying the WHERE clause. In other words, the query would result in a table scan, but happily all the columns involved in the WHERE condition are in an index, so the index is scanned instead.
In the second query though, there's no single index that contains all the columns in the WHERE clause. So MySQL resorts to a full table scan. In the case of the first query, it was using your index, but not to find the rows to check - in the special case of a COUNT() query, it could use the index to count rows. It was doing the equivalent of a table scan, but on the index instead of the table.
1) It seems you have two single-column indices. You can try to create a multi-column index.
For a detailed explanation why this is different than multiple single column indices, see the following:
http://www.mysqlfaqs.net/mysql-faqs/Indexes/When-does-multi-column-index-come-into-use-in-MySQL
2) Do you have a B-tree index on the expires_at column? Since you are doing a range query (<), that might give better performance.
http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
Best of luck!