Hi!

I have notice a very weird index selection when execution a query
in 3.23.36.


Here is an example:

The table is:

mysql> describe words;
+------------+----------------------+------+-----+--------------------
-+-------+
| Field      | Type                 | Null | Key | Default
| Extra |
+------------+----------------------+------+-----+--------------------
-+-------+
| id         | int(10) unsigned     |      | PRI | 0
|       |
| word_i     | char(50)             |      | MUL |
|       |
| product_id | int(10) unsigned     |      | MUL | 0
|       |
| position   | smallint(5) unsigned |      | MUL | 0
|       |
| sys_mdate  | datetime             |      |     | 0000-00-00 00:00:00
|       |
| sys_cdate  | datetime             |      |     | 0000-00-00 00:00:00
|       |
| sys_csite  | char(10)             |      |     |
|       |
| sys_msite  | char(10)             |      | MUL |
|       |
| sys_cp     | int(11)              |      |     | 0
|       |
| sys_mp     | int(11)              |      |     | 0
|       |
| sys_del    | tinyint(4)           |      | MUL | 0
|       |
+------------+----------------------+------+-----+--------------------
-+-------+
11 rows in set (0.00 sec)

It is used to index descriptions and names and other text data for
products and they quickly search for a product by specified keyword.

The indexes are:

+-------+------------+--------------------+--------------+------------
-+-----------+-------------+----------+--------+---------+
| Table | Non_unique | Key_name           | Seq_in_index | Column_name
| Collation | Cardinality | Sub_part | Packed | Comment |
+-------+------------+--------------------+--------------+------------
-+-----------+-------------+----------+--------+---------+
| words |          0 | PRIMARY            |            1 | id
| A         |       17848 |     NULL | NULL   |         |
| words |          1 | i_words_word_i     |            1 | word_i
| A         |        4462 |     NULL | NULL   |         |
| words |          1 | i_words_product_id |            1 | product_id
| A         |        1622 |     NULL | NULL   |         |
| words |          1 | i_words_position   |            1 | position
| A         |          64 |     NULL | NULL   |         |
| words |          1 | i_words_sysupd     |            1 | sys_msite
| A         |           1 |     NULL | NULL   |         |
| words |          1 | i_words_sysupd     |            2 | sys_mdate
| A         |         189 |     NULL | NULL   |         |
| words |          1 | i_words_qqq        |            1 | id
| A         |       17848 |     NULL | NULL   |         |
| words |          1 | i_words_qqq        |            2 | word_i
| A         |       17848 |     NULL | NULL   |         |
| words |          1 | i_words_qqq        |            3 | product_id
| A         |       17848 |     NULL | NULL   |         |
| words |          1 | i_words_qqq        |            4 | sys_del
| A         |       17848 |     NULL | NULL   |         |
| words |          1 | i_words_www        |            1 | product_id
| A         |        1622 |     NULL | NULL   |         |
| words |          1 | i_words_www        |            2 | sys_del
| A         |        1622 |     NULL | NULL   |         |
| words |          1 | i_words_eee        |            1 | word_i
| A         |        4462 |     NULL | NULL   |         |
| words |          1 | i_words_eee        |            2 | sys_del
| A         |        4462 |     NULL | NULL   |         |
| words |          1 | i_words_rrr        |            1 | sys_del
| A         |           1 |     NULL | NULL   |         |
| words |          1 | i_words_rrr        |            2 | product_id
| A         |        1622 |     NULL | NULL   |         |
| words |          1 | i_words_sys_del    |            1 | sys_del
| A         |           1 |     NULL | NULL   |         |
+-------+------------+--------------------+--------------+------------
-+-----------+-------------+----------+--------+---------+
17 rows in set (0.00 sec)

It looks like overkill but this is only for the testing perpose, so i
can see why MySQL will choose.


Now i want to find a product which contains both 'AMD' and 'DURON'. I
do a select where I join
the table with itself.

mysql> explain SELECT
    ->         w0.product_id
    -> FROM
    ->         words AS w0  LEFT JOIN words AS w1 ON w1.product_id =
w0.product_id AND w1.sys_del = 0
    -> WHERE
    ->         w0.sys_del=0 AND (w0.word_i LIKE 'amd%' AND w1.word_i
LIKE 'duron%') and w1.product_id=w0.product_id
    -> ;
+-------+-------+-----------------------------------------------------
----------------------------------+-----------------+---------+-------
+------+------------+
| table | type  | possible_keys
| key             | key_len | ref   | rows | Extra      |
+-------+-------+-----------------------------------------------------
----------------------------------+-----------------+---------+-------
+------+------------+
| w0    | range |
i_words_word_i,i_words_product_id,i_words_www,i_words_eee,i_words_rrr,
i_words_sys_del | i_words_eee     |      51 | NULL  |   25 | where
used |
| w1    | ref   |
i_words_product_id,i_words_www,i_words_rrr,i_words_sys_del
| i_words_sys_del |       1 | const |   10 | where used |
+-------+-------+-----------------------------------------------------
----------------------------------+-----------------+---------+-------
+------+------------+
2 rows in set (0.01 sec)

As you see it uses two indexes: i_word_eee for keyword match and
i_word_sys_del for the join. However
it is clear, that using i_words_www or i_words_rrr is a lot better.
Executing the query above takes
 8-9 seconds.


Now drop the index which mysql wants to use

mysql> alter table words drop index i_words_sys_del;

mysql> explain SELECT
    ->         w0.product_id
    -> FROM
    ->         words AS w0  LEFT JOIN words AS w1 ON w1.product_id =
w0.product_id AND w1.sys_del = 0
    -> WHERE
    ->         w0.sys_del=0 AND (w0.word_i LIKE 'amd%' AND w1.word_i
LIKE 'duron%') and w1.product_id=w0.product_id
    -> ;
+-------+-------+-----------------------------------------------------
------------------+--------------------+---------+---------------+----
--+------------+
| table | type  | possible_keys
| key                | key_len | ref           | rows | Extra      |
+-------+-------+-----------------------------------------------------
------------------+--------------------+---------+---------------+----
--+------------+
| w0    | range |
i_words_word_i,i_words_product_id,i_words_www,i_words_eee,i_words_rrr
| i_words_eee        |      51 | NULL          |   25 | where used |
| w1    | ref   | i_words_product_id,i_words_www,i_words_rrr
| i_words_product_id |       4 | w0.product_id |   11 | where used |
+-------+-------+-----------------------------------------------------
------------------+--------------------+---------+---------------+----
--+------------+
2 rows in set (0.01 sec)

AhA! Now it uses i_word_rrr !

mysql> SELECT
    ->         w0.product_id
    -> FROM
    ->         words AS w0  LEFT JOIN words AS w1 ON w1.product_id =
w0.product_id AND w1.sys_del = 0
    -> WHERE
    ->         w0.sys_del=0 AND (w0.word_i LIKE 'amd%' AND w1.word_i
LIKE 'duron%') and w1.product_id=w0.product_id
    -> ;
+------------+
| product_id |
+------------+
|     202101 |
|     202201 |
|     234201 |
|     234201 |
|     201801 |
|     201901 |
|     202001 |
|     234101 |
|     234201 |
|     234201 |
+------------+
10 rows in set (0.02 sec)


Voila!! 0.02 seconds agains 8 seconds.

So, why Mysql chooses the wrong index?

Regards,
Artem





---------------------------------------------------------------------
Before posting, please check:
   http://www.mysql.com/manual.php   (the manual)
   http://lists.mysql.com/           (the list archive)

To request this thread, e-mail <[EMAIL PROTECTED]>
To unsubscribe, e-mail <[EMAIL PROTECTED]>
Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php

Reply via email to