[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Простой индекс
forza
Добрый день.

Не знаю, не могу разобраться с глупой проблемой. Почему не используется индех при элементарной выборке?
Структура таблицы:

Цитата
CREATE TABLE `sc_webdata_main` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `domain` varchar(150) NOT NULL,
  `idn` varchar(150) NOT NULL,
  `md5domain` varchar(32) NOT NULL,
  `added_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `modified_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `price` decimal(30,2) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `ix_md5domain` (`md5domain`),
  KEY `ix_added` (`added_at`),
  KEY `ix_price` (`price`)
) ENGINE=InnoDB AUTO_INCREMENT=10999 DEFAULT CHARSET=utf8


Запрос:
explain select * from sc_webdata_main order by price desc limit 300, 10;

Результат:

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



Не понимаю почему по-умолчанию не используется индех (ix_price) и mysql сканирует все записи?

С таким вариантом выглядит лучше:
explain select * from sc_webdata_main force index (ix_price) order by price desc limit 3000, 1

Результат:

+----+-------------+-----------------+-------+---------------+----------+---------+------+------+----  ---+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------+----------+---------+------+------+--- ----+
| 1 | SIMPLE | sc_webdata_main | index | NULL | ix_price | 14 | NULL | 3010 | |
+----+-------------+-----------------+-------+---------------+----------+---------+------+------+--- ----+


Можно ли как-то обойтись без force index и почему даже если используется индекс - сканируются 3000 тыс. строк вместо 10? или я не совсем понимаю принцип работы...

_____________
Заработок для веб-разработчиков: CodeCanyon
Мое Портфолио
T1grOK
ПО умолчанию, Mysql, за редким исключением, очень тупо применяет(или не применяет) индекс к сортируемым полям. Честно говоря буквально пару раз в своей жизни видел, чтобы Mysql нормально применил индекс к сортируемому полю.

Понятное дело, там шуршит анализатор, оптимизатор, которые принимают решения по целесообразности той или иной стратегии выполнения запроса, но блин, эти решения однобоки))

_____________
Mysql, Postgresql, Redis, Memcached, Unit Testing, CI, Kohana, Yii, Phalcon, Zend Framework, Joomla, Open Cart, Ymaps, VK Api
GET
Цитата
ПО умолчанию, Mysql, за редким исключением, очень тупо применяет(или не применяет) индекс к сортируемым полям.


Тоже хотел что-то подобное написать, но постеснялся. Есть таблица на сайте к которой применяет (там участвует WHERE), а в другой не применяет, так и не понял почему.

_____________
Не тот велик, кто не падал, а тот кто падал и поднимался.
forza
ОК. Понятно, значит буду использовать конструкцию с "force index" (см. 2ой пример). Но такой вопрос. Если offset будет стоять 1 миллион, то он сначала переберет 1 миллион записей, а потом вернет 10 требуемых? Нельзя ли как-то оптимизировать этот процесс?

_____________
Заработок для веб-разработчиков: CodeCanyon
Мое Портфолио
sergeiss
Цитата (forza @ 11.12.2014 - 19:08)
Если offset будет стоять 1 миллион, то он сначала переберет 1 миллион записей, а потом вернет 10 требуемых? Нельзя ли как-то оптимизировать этот процесс?

А ты как хотел? Всё очень логично получается. Откуда запрос может узнать, какие именно 3000 записей пропустить? Только из того, что их перебрать. Так что то, что ты описал, это нормальная работа limit в БД.

Оптимизировать можно, но не во всех случаях. Например, если ты знаешь, какое у тебя было предыдущее значение, например, по полю price (в предыдущей подобной выборке, допустим при постраничной навигации, пусть это было число 1436.78). Тогда ты можешь написать так
select * from sc_webdata_main 
where price < 1436.78
order by price desc limit 1

При таком запросе будет обработана всего одна строка. Но это, как я уже сказал, "особый случай".

Можно попробовать выбрать этот порог подзапросом с лимитом "3000, 1", но там выбирать не всё, а только одно поле. Возможно, что это будет сделано быстрее (потому что в подзапросе будет выбираться существенно меньше данных). Но надо проверить, какая будет скорость.

select * from sc_webdata_main 
where price < (select price from sc_webdata_main order by price desc limit 3000, 1)
order by price desc limit 1



_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL

* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.

* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)

user posted image
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.