I have a MySQL InnoDB table with two INT columns, say col1 and col2. I'd like to add an index that will allow me to:
SELECT * from myTable WHERE col0=5 ORDER BY col1*col2 DESC
Is it possible to have an index that will support such a sorting or will i need to add a column that keeps that value (col1*col2) ?
Noam, see ORDER BY Optimization. If you want to use the index for sorting, it should be the same as the index, that is used in the WHERE clause and of course the value for sorting needs to be stored in it's own column. Here I generated a test table with 100k rows, that should match your situation.
1.) Adding ONE INDEX on two columns (this works for utlizing an index for both select and sort):
ALTER TABLE `test_data` ADD INDEX super_sort (`col0`,`sort_col`);
EXPLAIN SELECT * FROM `test_data` WHERE col0 = 50 ORDER BY sort_col;
key -> super_sort; Extra -> using where
(index is used for WHERE and SORT)
2.) Adding two indexes, one for WHERE and one for SORT (won't work)
ALTER TABLE `test_data` DROP INDEX `super_sort`;
ALTER TABLE `test_data` ADD INDEX (`col0`);
ALTER TABLE `test_data` ADD INDEX (`sort_col`);
EXPLAIN SELECT * FROM `test_data` WHERE col0 = 50 ORDER BY sort_col;
key -> col0; Extra -> Using where; Using filesort
(an index is used for WHERE, BUT NOT for sorting)
So the answer is: Yes, you will need a column, that keeps that value (col1*col2) AND you need ONE index on both columns: col0 (for the WHERE-clause) + sort_col (for sorting) like in first example. As soon, as you ORDER BY any calculation (e.g. col1*col2) no index can be used for sorting.
You can add new column that contains the value of col1*col2 and use it for sorting. Otherwise you can use SELECT * from myTable WHERE col0=5 ORDER BY col1*col2 DESC.
Related
I have question if I have tables with 3 columns (firstname, lastname , address ) as string/varchar(255)
and I have composite my_idx with 2 columns
CREATE INDEX my_idx ON my_table (firstname,lastname)
if I use sql , will it use my defined index ?
select * from my_table where address="zzz" and firstname="xxxx" and lastname="yyyy"
or should I use index columns as first left most condition
select * from my_table where firstname="xxxx" and lastname="yyyy" and address="zzz"
Thank you
First of all: if you prepend your Query with the keyword "EXPLAIN" it will print out all the indices it may use and which one MySQL choose.
From my understanding, yes it will use the index. The order of the fields in the Query is not relevant.
What matters is the order in the Index, but only if you are not providing all fields in the Query (or applying a function to the value or using e.g. the like operator for the rest of a string). If for example you only queried for lastname, the index can not be used. If you only queried for firstname, the index will be used. If you queried for firstname and address, the index will be used and so on...
I have a MySQL table of the form
CREATE TABLE `myTable` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`timestamp` datetime NOT NULL,
`fieldA` int(11) NOT NULL,
`fieldB` int(11) NOT NULL,
....
)
The table will have around 500,000,000 rows, with the remaining fields being floats.
The queries I will be using will be of the form:
SELECT * FROM myTable
WHERE fieldA= AND fieldB= AND timestamp>'' and timestamp<=''
ORDER BY timestamp;
At the moment I have two indices: a primary key on id, and a unique key on timestamp,fieldA,fieldB (hashed). At the moment, a select query like the above takes around 6 minutes on a reasonably powerful desktop PC.
What would the optimal index to apply? Does the ordering of the 3 fields in the key matter, and should I be using a binary tree instead of hashed? Is there a conflict between my primary key and the second index? Or do I have the best performance I can expect for such a large db without more serious hardware?
Thanks!
For that particular query adding an index to fieldA and fieldB probably would be optimal. Order of the columns in the index do matter.
Index Order
In order for Mysql to even consider using a particular index on the query the first column must be in the query, so for example:
alter table mytable add index a_b_index(a, b);
select * from mytable where a = 1 and b = 2;
The above query should use the index a_b_index. Now take this next example:
alter table mytable add index a_b_index(a, b);
select * from mytable where b = 2;
This will not use the index because the index starts with a, but a is never used in the query so mysql will not use it.
Comparison
Mysql will only use an index if you use equality comparison. So < and > won't use an index for that column, same with between
LIKE
Mysql does use indexes on the LIKE statement, but only when the % is at the end of the statement like this:
select * from mytable where cola like 'hello%';
Whereas these will not use a index:
select * from mytable where cola like '%hello';
select * from mytable where cola like '%hello%';
Hashed indexes are not used for ranges. They are used for equality comparisons only. Therefore, a hashed index cannot be used for the range portion of your query.
Since you have a range in your query, you should use a standard b-tree index. Ensure that fielda and fieldb are the first columns in the index, then timestamp. MySQL cannot utilize the index for searches beyond the first range.
Consider a multi-column index on (fielda, fieldb, timestamp).
The index should also be able to satisfy the ORDER BY.
To improve the query further, select only those three columns or consider a larger "covering" index.
UPDATE album SET x=1 WHERE store_id=:store_id && type=:type && time<:time
I have a Mysql update query, My question is how can I set up the index for this query
I create index in phpMyadmin, should I select store_id, type, time together and create one index?
if you are searching by store_id and type and time together then yes you can create INDEX for those three.
BUT,
if sometimes you are searching only by store_id then here you should use index only in store_id
if you search by store_id and type then index will be on those two columns.
so it depeneds what are columns you using to search.
here how to use to create what index you want.
ALTER TABLE `album` ADD INDEX `myindex` (`store_id`) --for store_id
ALTER TABLE `album` ADD INDEX `myindex` (`store_id` ,`type`,`time`) --for store_id and type and time
and so on ....
choose which one you want.
When setting up an index, the place to start is the where clause:
WHERE store_id=:store_id && type=:type && time<:time
Start with the equality comparisons. Then you can choose one column for inequality. For this query, the best index would have all three columns:
create index album_storeid_type_time on album(store_id, type, time);
I have a table where two columns are used in a where condition.
This is a MyIsam table and both columns hold text and use FULLTEXT as index.
The values in both columns are not unique.
The select statement works pretty slow.
Question is: can I simply remove the FULLTEXT index and use another index instead?
The query that is used is just as simple as possbile:
SELECT * FROM tbl WHERE col1=X AND col2=y and col3=z
Thanks!
ALTER TABLE `tableName` DROP INDEX `indexName` ,
ADD INDEX `indexName` ( `ColName` )
This shuld remove the old "FULLTEXT" index and add a "NOT FULTEXT" index.
I have query:
EXPLAIN SELECT * FROM _mod_news USE INDEX ( ind1 ) WHERE show_lv =1 AND active =1 AND START <= NOW( )
AND ( END >= NOW( ) OR END = "0000-00-00 00:00:00" ) AND id <> "18041" AND category_id = "3" AND leta =1 ORDER BY sort_id ASC , DATE DESC LIMIT 7
result:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE _mod_news ref ind1 ind1 2 const,const 11386 Using where; Using filesort
mysql is performing full table scan
ind1 =
ALTER TABLE `_mod_news` ADD INDEX ind1 ( `show_lv`, `active`, `start`, `end`, `id`, `category_id`, `leta`, `sort_id`, `date`);
I tested on following index, but nothing changes
ALTER TABLE `_mod_news` ADD INDEX ind1 ( `show_lv`, `active`, `start`, `end`, `id`, `category_id`, `leta`);
Question is: where i can learn how to create indexes on many where conditions? Or someone can explain how to tell to mysql to use and index and not to scan whole table.
Thanks.
I would suggest not forcing index. Mysql is a great at selecting the best possible index unless you have better understanding of the data you are querying.
You cannot use ORDER BY optimization because you are mixing the ASC and DESC in that part.
Therefore your only option is to create index such that:
constant values before range
integers before dates, dates before strings, smaller size vales before bigger size values
Creating a large index also adds an overhead to storage and insert-update time, so i would not add to index fields that are not eliminating a lot of rows (i.e 90% or rows have a value of 1 or i.e id<>"18041" but that most likely eliminates < 1% of rows).
If you want to learn more about optimizing: http://dev.mysql.com/doc/refman/5.0/en/select-optimization.html
Create multiple different indexes (on decent size of data you expect seeing in the table), see which one mysql chooses, benchmark them by forcing each one of them, then use your common sense to cut down on index space usage.
You can see from you EXPLAIN output that it is actually NOT performing a full table scan because in that case it would not display it using the index even when you are forcing it.
You can try with USE INDEX or FORCE INDEX