dbTalk Databases Forums  

Why index is not used for sorting?

comp.databases.mysql comp.databases.mysql


Discuss Why index is not used for sorting? in the comp.databases.mysql forum.



Reply
 
Thread Tools Display Modes
  #1  
Old   
SergeyPo
 
Posts: n/a

Default Why index is not used for sorting? - 05-18-2011 , 09:08 AM






Please help to optimize performance.
Query is "select * from addresses order by address limit 1000 offset
90000" runs very slowly.
Field 'address' is varchar(255), indexed.
Here are 'explain' result and 'describe addresses' result:

mysql> explain select * from addresses order by address;
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+
Quote:
id | select_type | table | type | possible_keys | key | key_len |
ref |
rows | Extra |
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+
Quote:
1 | SIMPLE | addresses | ALL | NULL | NULL | NULL | NULL |
103391 | Using filesort |
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+
1 row in set (0.00 sec)

mysql> describe addresses;
+---------+--------------+------+-----+---------+----------------+
Quote:
Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+----------------+
id | int(11) | NO | PRI | NULL | auto_increment |
address | varchar(255) | YES | MUL | NULL | |
header | int(11) | YES | MUL | NULL | |
kind | varchar(512) | YES | | NULL | |
+---------+--------------+------+-----+---------+----------------+
4 rows in set (0.20 sec)


--------------------------------------+
Quote:
addresses | CREATE TABLE `addresses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`address` varchar(255) DEFAULT NULL,
`header` int(11) DEFAULT NULL,
`kind` varchar(512) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `header__idx` (`header`),
KEY `idx_addresses` (`address`),
CONSTRAINT `addresses_ibfk_1` FOREIGN KEY (`header`) REFERENCES
`headers` (`id
`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=101825 DEFAULT CHARSET=utf8 |
+-----------
+-------------------------------------------------------------------

Reply With Quote
  #2  
Old   
Axel Schwenke
 
Posts: n/a

Default Re: Why index is not used for sorting? - 05-18-2011 , 11:21 AM






SergeyPo <ffvantaa (AT) gmail (DOT) com> wrote:

Quote:
Query is "select * from addresses order by address limit 1000 offset
90000" runs very slowly.
What is "very slowly"? Are you aware that ORDER BY ... LIMIT 90000,1000
has to read and sort 91000 rows anyway?

Quote:
mysql> explain select * from addresses order by address;
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+
| id | select_type | table | type | possible_keys | key | key_len |
ref |
rows | Extra |
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+
| 1 | SIMPLE | addresses | ALL | NULL | NULL | NULL | NULL |
103391 | Using filesort |
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+
Totally expected. You have 103000 rows in that table. The query has to
read all of them. No use for any index. The table scan + sort is very
probably faster than 103000 random row reads from that table.

Of course, if your query would be

SELECT address FROM addresses ORDER BY address

then MySQL could use a covering index read (don't read any row from
the table, but get all data from the index only). Since this is InnoDB,
you could even use SELECT address, id ...

But have you tried the EXPLAIN for SELECT ... LIMIT 90000,1000? Now
it should use a range scan on the index, skipping the first 90000
index records and then 1000 random row reads.


It /could/ be worth trying to rewrite the query like so:

SELECT * FROM addresses t1
JOIN
(SELECT id FROM addresses ORDER BY address LIMIT 90000,1000) t2
ON t1.id=t2.id

(or alternatively as subquery with IN)

Here the subquery could use the covering index and the outer would
use the PK to refer result rows.


XL

Reply With Quote
  #3  
Old   
SergeyPo
 
Posts: n/a

Default Re: Why index is not used for sorting? - 05-19-2011 , 03:30 AM



On 18 май, 20:21, Axel Schwenke <axel.schwe... (AT) gmx (DOT) de> wrote:
Quote:
SergeyPo <ffvan... (AT) gmail (DOT) com> wrote:
Query is "select * from addresses order by address limit 1000 offset
90000" runs very slowly.

What is "very slowly"? Are you aware that ORDER BY ... LIMIT 90000,1000
has to read and sort 91000 rows anyway?

mysql> explain select * from addresses order by address;
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+
| id | select_type | table | type | possible_keys | key | key_len |
ref |
rows | Extra |
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+
| 1 | SIMPLE | addresses | ALL | NULL | NULL | NULL | NULL |
103391 | Using filesort |
+----+-------------+-----------+------+---------------+------+---------
+------+-
-------+----------------+

Totally expected. You have 103000 rows in that table. The query has to
read all of them. No use for any index. The table scan + sort is very
probably faster than 103000 random row reads from that table.

Of course, if your query would be

SELECT address FROM addresses ORDER BY address

then MySQL could use a covering index read (don't read any row from
the table, but get all data from the index only). Since this is InnoDB,
you could even use SELECT address, id ...

But have you tried the EXPLAIN for SELECT ... LIMIT 90000,1000? Now
it should use a range scan on the index, skipping the first 90000
index records and then 1000 random row reads.

It /could/ be worth trying to rewrite the query like so:

SELECT * FROM addresses t1
JOIN
(SELECT id FROM addresses ORDER BY address LIMIT 90000,1000) t2
ON t1.id=t2.id

(or alternatively as subquery with IN)

Here the subquery could use the covering index and the outer would
use the PK to refer result rows.

XL
XL, Thank you for your reply!

mysql> explain select * from addresses order by address limit 1000
offset 90000;

+----+-------------+-----------+------+---------------+------+---------
+------+--------+----------------+
Quote:
id | select_type | table | type | possible_keys | key | key_len
ref |rows | Extra |
+----+-------------+-----------+------+---------------+------+---------
+------+--------+----------------+
Quote:
1 | SIMPLE | addresses | ALL | NULL | NULL | NULL
NULL |103391 | Using filesort |
+----+-------------+-----------+------+---------------+------+---------
+------+--------+----------------+

still no index is being used. If I run this select in console, it took
4.92 sec.


If, as you suggested, I explicitly select some fields, it seems
better:

mysql> explain select address, id from addresses order by address
limit 1000 off
set 90000;
+----+-------------+-----------+-------+---------------+---------------
+---------+------+-------+-------------+
Quote:
id | select_type | table | type | possible_keys | key
key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------------
+---------+------+-------+-------------+
Quote:
1 | SIMPLE | addresses | index | NULL | idx_addresses
768 | NULL | 91000 | Using index |
+----+-------------+-----------+-------+---------------+---------------
+---------+------+-------+-------------+

This one runs 1.75 sec.

This is great progress but for my app I need all fields in the result
set. When I try to add any other field to SELECT, it stops using the
index.

I tried the following query:
mysql> select * from addresses where addresses.id in (select id from
addresses order by address) limit 1000 offset 90000;
+-------+--------------------+--------+-----------------------+
Quote:
id | address | header | kind |
+-------+--------------------+--------+-----------------------+
90001 | 000000000000000000 | 135287 | AMR_FULL_TRANSLIT |
90002 | 000000000000000000 | 135287 | ADDRESS_FULL_TRANSLIT |
90003 | 000000000000000000 | 135288 | AMR_FULL_TRANSLIT |
90004 | 000000000000000000 | 135288 | ADDRESS_FULL_TRANSLIT |
90005 | 000000000000000000 | 135289 | AMR_FULL_TRANSLIT |
90006 | 000000000000000000 | 135289 | ADDRESS_FULL_TRANSLIT |
90007 | 000000000000000000 | 135290 | AMR_FULL_TRANSLIT |
90008 | 000000000000000000 | 135290 | ADDRESS_FULL_TRANSLIT |
90009 | 000000000000000000 | 135291 | AMR_FULL_TRANSLIT |
90010 | 000000000000000000 | 135291 | ADDRESS_FULL_TRANSLIT |
......
1000 rows in set (0.36 sec)
but this gives wrong result: note all those '000000...' values in
'address' column, actually they should contain text. Can you point me
what's wrong in my query? - it's really fast and definitely uses an
index.

At last, I tried your JOIN query, and with slight changes it worked
fast:

mysql> select * from addresses t1 join (select id from addresses order
by address) t2 on t1.id = t2.id limit 1000 offset 90000;

1000 rows in set (0.33 sec)

Thank you very much, and hope this post helps someone else to read
data from simple sorted table

Sergey

Reply With Quote
  #4  
Old   
Axel Schwenke
 
Posts: n/a

Default Re: Why index is not used for sorting? - 05-19-2011 , 04:52 AM



SergeyPo <ffvantaa (AT) gmail (DOT) com> wrote:
Quote:
mysql> explain select * from addresses order by address limit 1000
offset 90000;

+----+-------------+-----------+------+---------------+------+---------
+------+--------+----------------+
| id | select_type | table | type | possible_keys | key | key_len
| ref |rows | Extra |
+----+-------------+-----------+------+---------------+------+---------
+------+--------+----------------+
| 1 | SIMPLE | addresses | ALL | NULL | NULL | NULL
| NULL |103391 | Using filesort |
+----+-------------+-----------+------+---------------+------+---------
+------+--------+----------------+

still no index is being used. If I run this select in console, it took
4.92 sec.
Hmm. I wonder if that is an optimizer bug.

Quote:
If, as you suggested, I explicitly select some fields, it seems
better:

mysql> explain select address, id from addresses order by address
limit 1000 off
set 90000;
+----+-------------+-----------+-------+---------------+---------------
+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key
| key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+---------------
+---------+------+-------+-------------+
| 1 | SIMPLE | addresses | index | NULL | idx_addresses
| 768 | NULL | 91000 | Using index |
+----+-------------+-----------+-------+---------------+---------------
+---------+------+-------+-------------+

This one runs 1.75 sec.

This is great progress but for my app I need all fields in the result
set. When I try to add any other field to SELECT, it stops using the
index.
Yep. The index on (address) is no longer a covering index then.

http://dom.as/2007/01/26/mysql-cover...x-performance/
http://www.xaprb.com/blog/2006/07/04...optimizations/

Quote:
I tried the following query:
mysql> select * from addresses where addresses.id in (select id from
addresses order by address) limit 1000 offset 90000;
<snip>

Quote:
1000 rows in set (0.36 sec)

but this gives wrong result
Yes. Because the query is wrong. Should have been

select * from addresses where addresses.id in
(select id from addresses order by address limit 1000 offset 90000);

notice the position of the closing bracket?


XL

Reply With Quote
Reply




Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.3
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.