Sorting of my mySQL table does not use the index and I don't know why.
I've got:
CREATE TABLE IF NOT EXISTS `test` (
`a` int(11) NOT NULL,
`b` int(11) NOT NULL,
KEY `kk` (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
and this:
EXPLAIN SELECT *
FROM test
ORDER BY a
as well as this
EXPLAIN SELECT *
FROM test
USE INDEX ( kk )
ORDER BY a
gives me this:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE test ALL NULL NULL NULL NULL 10009 Using filesort
I'd like not to see this filesort, and use the key kk to sort my table. What am I doing wrong?
Thank you for your posts guys, they answer my question! However, now I do not undestand what is meant by "table scan" and "filesort"? Even if I am selecting all fields and all rows of a table, isn't it faster to sort that table by one column by walking in O(n) the internal tree of the index of that column (and then looking up in the table file the extra columns requested, in O(1) for each row => the index file stores each row's physical position in the table file, or?), than to sort e.g. by quick sort in O(n * log n) the (potentially) randomly stored rows in the table file, without touching the index? I guess my understanding of how indexes work in mySQL is wrong.
Answer: Oracle SQL not using an index is a common complaint, and it's often because the optimizer thinks that a full-scan is cheaper than index access.
Indexes consume disk space. Indexes degrade the performance of INSERT, UPDATE and DELETE queries – when data is updated, the index needs to be updated together with it. MySQL does not protect you from using multiple types of indexes at the same time.
Introduction to MySQL indexesAn index is a data structure used to locate data without scanning all the rows in a table for a given query. Indexes help retrieve data faster. Indexes are not visible to the users. They help speed up queries that require a search.
Write "explain " in front of your query. The result will tell you which indexes might be used.
@zerkms is correct, by reading all the rows in the table, MySQL decides it's going to have to read the majority of the table anyway so there's no need to read the index as well. The optimizer changes behavior if you select a subset of the table.
For example, I created a table like yours and filled it with 16384 rows, with random integers between 0 and 1000000. Then I tried EXPLAIN for different subsets of the table, first 15% of the table, then 17%, then 19%.
mysql> EXPLAIN SELECT * FROM test where a < 150000 ORDER BY a;
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | test | range | kk | kk | 5 | NULL | 2272 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
mysql> EXPLAIN SELECT * FROM test where a < 170000 ORDER BY a;
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | test | range | kk | kk | 5 | NULL | 2560 | Using where |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
mysql> EXPLAIN SELECT * FROM test where a < 190000 ORDER BY a;
+----+-------------+-------+------+---------------+------+---------+------+-------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+-------+-----------------------------+
| 1 | SIMPLE | test | ALL | kk | NULL | NULL | NULL | 16384 | Using where; Using filesort |
+----+-------------+-------+------+---------------+------+---------+------+-------+-----------------------------+
You can also convince it to use the index by decreasing the columns until you are just selecting the columns of the index. It'll decide to read the index alone, and not touch the table. You can define an index with extra columns if you need to, even if those columns are not needed for searching or sorting.
mysql> ALTER TABLE test ADD KEY kk2 (a,b);
mysql> EXPLAIN SELECT a,b FROM test ORDER BY a;
+----+-------------+-------+-------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE | test | index | NULL | kk2 | 10 | NULL | 16384 | Using index |
+----+-------------+-------+-------+---------------+------+---------+------+-------+-------------+
Following what I said above - mysql estimates it to be more efficient to use full scan.
To get it using index you need to add some WHERE
that would limit it to reasonable number of rows returned (say 50)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With