2009-12-04 3 views
1

Я пытаюсь использовать следующий запрос в таблице с записями ~ 200k. Есть всевозможные другие поля, которые можно отфильтровать, но это базовый пример.Стратегия индексации MySQL

SELECT b.isbn FROM books b 
WHERE 
b.price IS NOT NULL AND 
b.deleted = '' AND 
b.publication_date <= '2009-12-04' AND 
(
    b.subject1_id IN ('CAT1','CAT2','CAT3','CAT4','CAT5') OR 
    b.subject2_id IN ('CAT1','CAT2','CAT3','CAT4','CAT5') OR 
    b.subject3_id IN ('CAT1','CAT2','CAT3','CAT4','CAT5') 
) 

В настоящее время у меня есть отдельный индекс на всех этих областях, и этот запрос занимает ~ 4.5 секунд, что слишком долго. EXPLAIN списки NULL под ключ.

Я также попытался создать один большой индекс, который включал все поля в указанном выше запросе, но EXPLAIN показывает, что этот многопоточный индекс не используется.

Как я могу индексировать эти поля, чтобы ускорить мои запросы?

EDIT: Вот мои текущие показатели (ни один из которых, кажется, можно использовать по запросу):

  • индекс (цена)
  • индекс (удален)
  • индекс (publication_date)
  • индекс (subject1_id)
  • индекс (subject2_id)
  • индекс (subject3_id)
  • индекс (цена, удаление, publication_date, subject1_id, subject2_id, subject3_id)

EDIT2: За ответ ʞɔıu в - после нормализации таблиц и используя в основном его запрос, он делает его ускорить некоторые (время составляет ~ 3,5 секунды сейчас), но не столько, сколько я ищу. Я проиндексировал новую таблицу как PRIMARY KEY (isbn, subject_id), и этот индекс используется для соединения.

EDIT3: Я добавил дополнительный указатель на вторую таблицу (subject_id, isbn), что помогает. Добавление другого индекса, о котором упоминается ниже ʞɔıu, помогает немного, но используется только тогда, когда я использую «FORCE INDEX» в запросе. Сейчас около 1,5 секунд. Есть ли надежда получить его намного ниже?

+0

попробуйте добавить еще один индекс (при условии, ISBN) по теме таблицы –

+0

также с учетом того же присоединиться добавить индекс (ISBN, publish_date, deleted, price) в таблице книг –

ответ

3

Вам необходимо нормализовать схему, прежде чем индексирование будет иметь любую помощь в этом случае.

Вы можете создать еще одну таблицу, содержащую (предмет, ISBN), добавить индексы на книги и тему, а затем присоединиться к этой таблице, как:

select b.isbn from books b 
inner join book_subject bs on bs.isbn=b.isbn 
where 
    b.price is not null and b.deleted != 'DELETED' 
    AND b.publication_date <= '2009-12-04' 
    AND bs.subject in ('CAT1', 'CAT2'...) 

Правило № 1 (в буквальном смысле) в схеме нормализации: "no repeating groups". Наличие операции OR в предложении where в трех столбцах объекта препятствует тому, чтобы вы могли использовать индекс для этой части запроса.

(обновлено, чтобы отразить, что ISBN является первичным ключом)

+0

Ну, причина, по которой это не нормируется, - это только потому, что это формат исходных данных. Будет ли необходимость присоединяться к таблице из 200 тыс. Записей с другой таблицей размером до 600 тыс. Записей, действительно поможет повысить эффективность запроса? – Wickethewok

+0

Скорее всего, потому, что он сможет использовать индекс, а стоимость будет функцией * log * количества проверенных строк. –

+0

Довольно хороший материал - вы можете добавить свои комментарии к моему вопросу к своему ответу, так как дополнительный индекс в таблице темы был очень важен. – Wickethewok

0

Я бы больше думать о том, что ваш запрос на самом деле означает, и что может помочь проложить путь к вашему ответу.

Давайте попробуем его, чтобы показать вам проблему.

SELECT b.isbn FROM books b 
WHERE 
b.price IS NOT NULL AND 
b.deleted != 'DELETED' AND 
b.publication_date <= '2009-12-04' AND 
(
    b.subject1_id = 'CAT1' OR 
    b.subject1_id = 'CAT2' OR 
    b.subject1_id = 'CAT3' OR 
    b.subject1_id = 'CAT4' OR 
    b.subject1_id = 'CAT5' OR 
    b.subject2_id = 'CAT1' OR 
    b.subject2_id = 'CAT2' OR 
    b.subject2_id = 'CAT3' OR 
    b.subject2_id = 'CAT4' OR 
    b.subject2_id = 'CAT5' OR 
    b.subject3_id = 'CAT1' OR 
    b.subject3_id = 'CAT2' OR 
    b.subject3_id = 'CAT3' OR 
    b.subject3_id = 'CAT4' OR 
    b.subject3_id = 'CAT5' 

) 

Там, очевидно, не какой-либо индекс будет использовать за них для (цены, удаляемые, дата_публикация, subject1) и так далее для других субъектов.

Какие поля содержатся в индексе?

+0

См. Мои выше правки относительно индексированных полей. – Wickethewok

0

В отношении поста ники:

создать еще одну таблицу, содержащую (при условии, book_id), добавить индексы книги и тема:

не было бы чище, чтобы иметь

select b.isbn from books b 

where 
#various table b where restrictions 

AND b.isbn IN (
    Select isbn 
    from book_subject bs 
    where bs.subject IN ('CAT1', 'CAT2' ...) 
) 
+0

Я немного растерялся относительно вашего ответа. «isbn» является основным ключом, если это помогает. – Wickethewok

+0

Для этого запроса потребуется временная таблица для хранения промежуточных результатов подзапроса; метод внутреннего соединения не будет. Операции подзапроса mysql не очень оптимизированы по сравнению с другими СУБД. –

+0

обновлено, чтобы использовать isbn как PK – Zak

0

Прежде всего: MySQL может использовать только один указатель для таблицы во время выбора. Он пытается выбрать наилучший индекс, но иногда сервер не может решить по нескольким причинам. Наличие нескольких индексов только для одного поля помогло бы, если бы у вас было много операторов, работающих только с одним предложением where.

Для оптимизации здесь: Вам нужно создать индекс, который делает включать поля

price 
deleted 
publication_date 

НЕ включают категории, так как вы используете OR пункт.

ALTER TABLE `test`.`books` ADD INDEX `idxPriceDeletedPublication`(`price`, `deleted`, `publication_date`); 

Это должно затем дать вам следующий EXPLAIN вывод:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: b 
     type: range 
possible_keys: idxPriceDeletedPublication 
      key: idxPriceDeletedPublication 
     key_len: 5 
      ref: NULL 
     rows: 1 
     Extra: Using where 
1 row in set (0.00 sec) 
+0

, он не сможет индексировать удаленный столбец; вы не можете индексировать не равно. Лучшей стратегией будет запрос на deleted = 'NOTDELETED' или что-то противоположное состоянию DELETED –

+0

Я добавил этот трехкомпонентный индекс. MySQL не будет использовать его по моему запросу по умолчанию, и когда я использую «FORCE INDEX», на самом деле это занимает 13 секунд по какой-то причине. Противоположность 'DELETED' is '' и ʞɔıu правильно, что я должен использовать это. – Wickethewok

Смежные вопросы