MySQL оптимизирует запрос по дате заказа

0

Я сделал все возможное, чтобы решить следующие два простых запроса, но для каждого результата из 10 строк он сканирует полную таблицу или не менее 10 тыс. строк. В настоящее время в таблице книг находится 20000 строк.

ALTER TABLE books ADD INDEX search_INX (`book_status`, `is_reviewed`,`has_image`,`published_date`)

mysql> EXPLAIN SELECT book_id FROM books ORDER BY published_date DESC LIMIT 10;
+----+-------------+-------+-------+---------------+------------+---------+------+-------+-----------------------------+
| id | se ref  |lect_type | table | type  | possible_keys | key        | key_len | rows  | Extra                       |
+----+-------------+-------+-------+---------------+------------+---------+------+-------+-----------------------------+
|  1 | SIMPLE      | books | index | NULL          | search_INX | 11      | NULL | 20431 | Using index; Using filesort | 
+----+-------------+-------+-------+---------------+------------+---------+------+-------+-----------------------------+

mysql> EXPLAIN SELECT book_id FROM books WHERE book_status='available' AND is_reviewed=true AND has_image=true ORDER BY published_date DESC LIMIT 10;
+----+-------------+-------+------+---------------+------------+---------+-------------------+-------+--------------------------+
| id | select_type | table | type  ref               || possible_keys | key        | key_len | rows  | Extra                    |
+----+-------------+-------+------+---------------+------------+---------+-------------------+-------+--------------------------+
|  1 | SIMPLE      | books | ref  | search_INX    | search_INX | 3       | const,const,const | 10215 | Using where; Using index | 
+----+-------------+-------+------+---------------+------------+---------+-------------------+-------+--------------------------+

mysql> EXPLAIN SELECT book_id FROM books WHERE book_status='available' AND is_reviewed=true AND has_image=true ORDER BY published_date DESC LIMIT 10\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: books
         type: ref
possible_keys: search_INX
          key: search_INX
      key_len: 3
          ref: const,const,const
         rows: 10215
        Extra: Using where; Using index
1 row in set (0.00 sec)

Create Table: CREATE TABLE `books` (
  `book_id` int(10) unsigned NOT NULL auto_increment,
  `has_image` bit(1) NOT NULL default '',
  `is_reviewed` bit(1) NOT NULL default '\0',
  `book_status` enum('available','out of stock','printing') NOT NULL default 'available',
  `published_date` datetime NOT NULL,
  PRIMARY KEY  (`book_id`),
  KEY `search_INX` (`is_reviewed`,`has_image`,`book_status`,`published_date`)
) ENGINE=InnoDB AUTO_INCREMENT=162605 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

Кто-нибудь знает, как решить эту проблему?

  • 1
    @jason: jason: я не вижу проблемы, большие строки вызваны низкой кардинальностью, может быть, вы попытаетесь выполнить запрос, и посмотрите, насколько он плох
  • 0
    Я не знаком с MySQL (но я с другими). Строка «KEY search_INX ( is_reviewed , has_image , book_status , published_date )» выглядит как составной ключ. Это?
Показать ещё 13 комментариев
Теги:

6 ответов

1
Лучший ответ

Кроме того, в столбце mysql in rows указано не количество затронутых строк, а количество строк приблизительное, которое может быть затронуто, исключая LIMIT.

2

Мощность:

KEY `search_INX` (`is_reviewed`,`has_image`,`book_status`,`published_date`)

... плохой. Если бы вы поставили publish_date на передний план, это ускорит ваш запрос. Кроме того, почему вы индексируете is_reviewed и has_image? Булевы столбцы даже не могут индексироваться в подобных SQL Server, так как нет смысла делать это (опять же, мощность). Либо перегруппируйте свой ключ, либо поместите уникальный ключ в колонку, о которой я упоминал.

  • 0
    Это правильное решение. Попробуй. Вот увидишь.
  • 0
    Если я переместил опубликованную дату на первую позицию в индексе, она отсканирует 20К строк, если я сохраню порядок полей, то она отсканирует 10К строк. Ясно, что порядок полей важен.
Показать ещё 11 комментариев
1

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

  • 0
    его там просто прокрутите вправо, вы увидите это
  • 0
    @ Джейсон: нет, нет
Показать ещё 2 комментария
0

@Zerkms @jason Я просто подумал о другом способе решить эту проблему.

Это неортодоксально, но будет работать. Если ваш первичный ключ был (publish_date, book_id) с сортировкой DESC, вы легко сможете получить последние 10 результатов. Механизм запроса сканирует таблицу, применяя предложение where, пока не найдет 10 результатов, а затем закроется.

Это сработало бы отлично. Просто добавьте еще один индекс в book_id, если вам нужно специально запросить book_id.

Причиной этого является то, что БД естественно хранит книги по дате (InnoDB использует кластерные индексы), что именно то, что вы пытаетесь запросить.

  • 0
    Я читал в другом месте, что DESC не возможно в MySQL. Тем не менее, это будет работать. Поочередно сначала инвертируйте дату. Википедия - пример использования инверсии для создания отрицательной последовательности «DESC».
0

Если вы используете команду FORCE INDEX, это помогает?

  • 0
    индекс уже показан в Explain, поэтому нет необходимости использовать FORCE INDEX
0

Я не эксперт по индексированию, но могу ли вы создать индекс только на publish_date, а также индекс, который вы указали на всех четырех полях?

ALTER TABLE books DROP INDEX `search_INX`;
ALTER TABLE books ADD INDEX `published_INX` (`published_date`);
  • 0
    book_id , ваши ключи в настоящее время являются первичным ключом для book_id и book_id из нескольких столбцов для 4 разных столбцов, так что вы можете захотеть иметь ключ только для published_date чтобы оператор ORDER BY работал более эффективно.
  • 0
    Я сделал, но это не имеет никакого значения. После использования Force Index сканирует полную таблицу
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню