Люди, разбирающиеся в оптимизации запросов MySQL, помогите, плиз.
Система FreeBSD 4.7, MySQL 3.23.49 и 4.0.16 (проверено на обоих).
Ситуация такая:
есть таблица session:
mysql> desc session;
+----------------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+----------------------+------+-----+---------+-------+
| session_id | int(10) unsigned | | PRI | 0 | |
| session_length | smallint(5) unsigned | | MUL | 0 | |
+----------------+----------------------+------+-----+---------+-------+
у неё такие индексы (несущественные поля описания я убрал для удобства):
mysql> show index from session;
+---------+-----+----------------+----------------+-----+--------+---------+
| Table | N_u | Key_name | Column_name | Col | Cardin | Index_t |
+---------+-----+----------------+----------------+-----+--------+---------+
| session | 0 | PRIMARY | session_id | A | 606947 | BTREE |
| session | 1 | session_length | session_length | A | 350 | BTREE |
+---------+-----+----------------+----------------+-----+--------+---------+
делаем такой запрос:
mysql> explain select session_length from session where session_length > 0;
+---------+-------+----------------+----------------+---------+------+--------+--------------------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+---------+-------+----------------+----------------+---------+------+--------+--------------------------+
| session | range | session_length | session_length | 2 | NULL | 309581 | Using where; Using index |
+---------+-------+----------------+----------------+---------+------+--------+--------------------------+
здесь, как видим, всё нормально, индекс используется...
Теперь добавим в выборку поле session_id:
mysql> explain select session_id, session_length from session where session_length > 0;
+---------+------+----------------+------+---------+------+--------+-------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+---------+------+----------------+------+---------+------+--------+-------------+
| session | ALL | session_length | NULL | NULL | NULL | 606947 | Using where |
+---------+------+----------------+------+---------+------+--------+-------------+
Опачки! Объясните, какого хрена он вдруг не захотел юзать очевидный индекс, какого хрена он полез делать фулскан? То же самое будет, если поменять в этом тесте поля session_id и session_length местами. Я пробовал воздействовать на таблицу с помощью myisamchk - ничего не помогает.
Поэкспериментировав с вариациями запросов выделил следующие ситуации:
mysql> explain select session_id, session_length from session where session_length > 3;
+---------+-------+----------------+----------------+---------+------+-------+-------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+---------+-------+----------------+----------------+---------+------+-------+-------------+
| session | range | session_length | session_length | 2 | NULL | 80225 | Using where |
+---------+-------+----------------+----------------+---------+------+-------+-------------+
т.е. когда мы увеличили нижнюю границу поиска до 3, то индекс он юзать стал, причём именно с трёх и выше, 1 и 2 - то же самое (не работает).
mysql> explain select session_id, session_length from session where session_length = 0;
+---------+------+----------------+----------------+---------+-------+--------+-------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+---------+------+----------------+----------------+---------+-------+--------+-------+
| session | ref | session_length | session_length | 2 | const | 297366 | |
+---------+------+----------------+----------------+---------+-------+--------+-------+
т.е. если знак "больше" меняем на знак "равно" к чему угодно, то индекс тоже юзается.
mysql> explain select session_id, session_length from session where session_length != 0;
+---------+------+---------------+------+---------+------+--------+-------------+
| table | type | possible_keys | key | key_len | ref | rows | Extra |
+---------+------+---------------+------+---------+------+--------+-------------+
| session | ALL | NULL | NULL | NULL | NULL | 606947 | Using where |
+---------+------+---------------+------+---------+------+--------+-------------+
т.е. для "не равно" поведение такое же, как и для "больше".
Эксперименты также показали, что изменение порядка полей в выборке, или убирании session_length из неё не влияют на поведение. ведут себя одинаково - проверял.
Помогите, плиз, в реальной задаче у меня таблица на несколько миллионов, причем она ещё и объединяется с ещё более несколькомиллионной, так что фулскан тут совсем не в тему. Как с этим бороться?
Заранее всем спасибо.