Задавайте вопросы, мы ответим
Вы не зашли.
Здравствуйте.
Есть вот такая табличка:
mysql> DESCRIBE `friends_history`;
+------------+----------------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------------------+------+-----+-------------------+-----------------------------+
| _id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| user_id | int(11) unsigned | NO | PRI | NULL | |
| type | enum('remove','add') | NO | | NULL | |
| users_list | mediumtext | NO | | NULL | |
| date | timestamp | NO | MUL | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+------------+----------------------+------+-----+-------------------+-----------------------------+
mysql> SHOW INDEXES FROM `friends_history`;
+-----------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| friends_history | 0 | PRIMARY | 1 | _id | A | 49470030 | NULL | NULL | | BTREE | | |
| friends_history | 0 | PRIMARY | 2 | user_id | A | 49470030 | NULL | NULL | | BTREE | | |
| friends_history | 1 | date | 1 | date | A | 49470030 | NULL | NULL | | BTREE | | |
| friends_history | 1 | user_id+date | 1 | user_id | A | 2748335 | NULL | NULL | | BTREE | | |
| friends_history | 1 | user_id+date | 2 | date | A | 49470030 | NULL | NULL | | BTREE | | |
+-----------------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
И вот такой к ней запрос:
mysql> EXPLAIN SELECT `type`,`users_list` FROM `friends_history` WHERE `user_id` = 1052662 ORDER BY `date` DESC;
+----+-------------+-----------------+------+---------------+--------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+--------------+---------+-------+------+-------------+
| 1 | SIMPLE | friends_history | ref | user_id+date | user_id+date | 4 | const | 33 | Using where |
+----+-------------+-----------------+------+---------------+--------------+---------+-------+------+-------------+
Объясните, пожалуйста, из-за чего здесь USING WHERE? Можно ли его побороть?
Второй вопрос состоит в том, что запрос без сортировки исправно выдаёт отсортированный по date результат (date в нашем случае - дата добавления записи). Можно ли полагаться на это? Ведь по идеи mysql не обязан этого делать.
mysql> EXPLAIN SELECT `type`,`users_list` FROM `friends_history` WHERE `user_id` = 1052662;
+----+-------------+-----------------+------+---------------+--------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+------+---------------+--------------+---------+-------+------+-------+
| 1 | SIMPLE | friends_history | ref | user_id+date | user_id+date | 4 | const | 33 | |
+----+-------------+-----------------+------+---------------+--------------+---------+-------+------+-------+
Спасибо.)
Неактивен
На колонке, которая поддерживает NULL, — нельзя. NULLы то отсеивать надо
как-то
Полагаться не стоит, так как это не документированная особенность MyISAM.
Например, удаление строки, а потом добавление новой, вставит строку физи-
чески не в конец таблицы, а в освободившееся место, и недокументированная
сортировка нарушится. Ну и если будете переходить на InnoDB, сможете это
сделать куда проще, если не будете использовать такие особенности
Неактивен
Эм...)
Так никакая из колонок NULL и не поддерживает.
И это уже InnoDB.
mysql-5.5.8
Может так понятнее
CREATE TABLE `friends_history` (
`_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL,
`type` enum('remove','add') NOT NULL COMMENT '1-add; 0-remove;',
`users_list` mediumtext NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`_id`,`user_id`),
KEY `date` (`date`),
KEY `user_id+date` (`user_id`,`date`)
) ENGINE=InnoDB AUTO_INCREMENT=47224987 DEFAULT CHARSET=utf8
Отредактированно rs7 (30.01.2011 12:29:48)
Неактивен
Да, так куда понятнее, а то смотрел на DEFAULT NULL
В InnoDB строки сортируются по PRIMARY KEY всегда, на это можно полагаться.
Соответственно, если _id у Вас растет честным автоинкрементом, то он будет
расти с датой в том числе Кстати, а зачем там user_id в PK?
Что касается Using where в данном случае — смотрите последний комментарий
Тобиаса в http://bugs.mysql.com/bug.php?id=30733 . Впрочем, насколько я пони-
маю, это проблема отображения, а не выполнения запроса.
Неактивен
paulus написал:
В InnoDB строки сортируются по PRIMARY KEY всегда, на это можно полагаться.
Соответственно, если _id у Вас растет честным автоинкрементом, то он будет
расти с датой в том числе
Кстати, а зачем там user_id в PK?
Что касается Using where в данном случае — смотрите последний комментарий
Тобиаса в http://bugs.mysql.com/bug.php?id=30733 . Впрочем, насколько я пони-
маю, это проблема отображения, а не выполнения запроса.
Спасибо. Автоинкремент у меня не совсем честный - стоит innodb_autoinc_lock_mode = 2. Но учитывая специфику приложения - полагаться можно.
Добавлено секционирование по этому полю.
Почитал. Интересно, что ситуация у человека наоборот: у него при использование префикса многостолбцового индекса возникает USING WHERE, у меня же - только если включить сортировку по второй части индекса ORDER BY `date`. Причём, появляется не USING FILESORT, как если бы эта самая, вторая часть, не подхватывалась, а USING WHERE - типа индекс вообще не используется. Но, при этот, тот же самый EXPLAIN сообщает обратное.
Если, как Вы считаете, это проблема отображения, то как это правильно проверить? Выполнить запрос несколько раз пока не устаканется время выполнения и последний результат считать правильным? SQL_NO_CACHE, как я понимаю, спасает только от кэша запросов, а более глубокие процессы кэширования принудительно выключить нельзя. Потому как время выполнения запроса в первые разы больше чем в следующие.
Отредактированно rs7 (31.01.2011 04:59:52)
Неактивен
USING WHERE — не означает, что индекс не используется. Это означает,
что результат дополнительно проверяется на соблюдение условий. Наличие
индекса при вытаскивании данных можно увидеть в столбце key. Что касается
Тобиаса — у него ситуация такая же — используется левая часть индекса
(key_len=4, только по _id в Вашем случае), и отображается «Using where».
А что Вы называете более глубокими процессами кэширования? При первом
проходе Вы вытаскиваете с диска страницы индекса, которых еще там не
было. При втором проходе они там уже есть, поэтому на диск за ними идти
не нужно.
Неактивен
Спасибо за ответы.
Неактивен