2013-09-25 2 views
0

У меня есть запрос, который занимает много времени, и мне было интересно, есть ли лучший способ сделать это? Возможно, с присоединениями?Уточнение этого запроса MySQL?

В настоящее время занимает ~ 2,5 секунды, что слишком долго.

Чтобы немного объяснить структуру: у меня есть продукты, «темы» и «категории». Продукту может быть присвоено любое количество тем или категорий. Таблицы themeitems и categoryitems связывают таблицы, чтобы связать идентификатор категории/темы с идентификатором продукта.

Я хочу получить список всех продуктов с хотя бы одной темой и категорией. Запрос я получил на данный момент ниже:

SELECT * 
FROM themes t, themeitems ti, products p, catitems ci, categories c 
WHERE t.ID = ti.THEMEID 
AND ti.PRODID = p.ID 
AND p.ID = ci.PRODID 
AND ci.CATID = c.ID 

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

Любая помощь в правильном направлении будет замечательной!

Edit: EXPLAIN ниже

EXPLAIN

+1

Можете ли вы разместить ЭКСПЛАЙН? –

+0

Да, редактируемый вопрос. – Michael

+0

Сколько строк возвращается? – zerkms

ответ

1

Используйте правильно соединения и обеспечить наличие индексов на полях, используемых в РЕГИСТРИРУЙТЕСЬ является стандартным ответом на этот вопрос.

SELECT * 
FROM themes t 
INNER JOIN themeitems ti ON t.ID = ti.THEMEID 
INNER JOIN products p ON ti.PRODID = p.ID 
INNER JOIN catitems ci ON p.ID = ci.PRODID 
INNER JOIN categories c ON ci.CATID = c.ID 

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

+1

«Спецификация JOINs помогает механизму запросов» --- это не так. Оптимизатор выполняет ваш запрос и OP одинаково (если быть точным - один из них переписывается в другой перед оценкой) – zerkms

+1

JOINs хороши для читаемости (и при этом не забудьте добавить условие присоединения.) Но я согласен, что здесь отсутствуют индексы , –

+0

Также было бы целесообразно перечислить, какие индексы требуются. – zerkms

0

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

0

Просто выберите меньшее количество данных - это очевидное решение здесь.

Почему каждый раз, когда вы запускаете запрос, вам нужно знать каждый столбец и каждую строку? Решение любого из этих трех факторов улучшит производительность.

Я хочу, чтобы получить список всех продуктов, по крайней мере, одной темы и категории

Это скорее означает, что вы не заботитесь которые темы и категории, в этом случае .... .

SELECT p.* 
FROM themeitems ti, products p, catitems ci 
WHERE p.ID = ti.PRODID 
AND p.ID = ci.PRODID 

Это может быть возможно сделать запрос запуска значительно быстрее, - но вы не представили подробную информацию о структуре таблицы, индексы, объем данных, тип двигателя, конфигурации кэша запроса, частота обновления данных, частота, с которой запрос выполняется .....

обновление

Теперь, когда вы предоставили план объяснить то, что очевидно, у вас есть очень небольшое количество данных И НЕТ ОТНОСИТЕЛЬНО ИНДЕКСОВ !!!!!

Как минимум вы должны добавить указатели на внешний ключ продукта в таблицах themeitems и catitems.В самом деле, первичными ключами для этих таблиц должны быть идентификаторы id и категории идентификатора продукта и категории, и поскольку вероятность того, что у вас будет больше продуктов, чем категорий или тем, тогда поля должны быть в этом порядке в индексах. (Т.е. PRODID, CATID, а не CatID, PRODID)

Update2

Учитывая требование «чтобы получить список всех продуктов, по крайней мере, одной темы и категории», это может быть еще быстрее (но большие выигрыши уменьшения количества соединений и добавления нужных индексов) для ....

SELECT p.* 
FROM product p 
INNER JOIN (
    SELECT DISTINCT ti.PRODID 
    FROM themeitems ti, catitems ci 
    WHERE ti.PRODID=ci.PRODID 
) i ON p.id=i.PRODID 
+0

«очень маленькие объемы данных» - умножить все значения строк и получить сотни миллионов – zerkms

+0

Нет - даже на очень быстром оборудовании СУБД не будет обрабатывать «сотни миллионов» записей за 2,5 секунды (и даже тогда декартово продукт сотен миллионов - это не то, что я бы назвал особенно большим). И даже при отсутствии индексации объединения будут оптимизированы как операции слияния – symcbean

+0

«даже на очень быстром оборудовании, которое СУБД не будет обрабатывать» --- это прогноз (оптимизация) оптимизатора запросов. Предположим, что это верхняя граница. Моя точка зрения заключалась в том, что мы не можем получить реальные цифры из объяснения, поскольку данных недостаточно. Таким образом, вы не можете сказать «очень маленькие объемы данных», так как реальное количество возвращаемых строк может варьироваться от 0 до 100 миллионов в зависимости от фактических данных. – zerkms

1

Ваш запрос медленно, потому что у вас нет каких-либо индексов таблиц.

Try:

create unique index pk on themes (ID) 
create index fk on themeitems(themeid, prodid) 
create unique index pk on products (id) 
create index fk catitems(prodid, catid) 
create unique index pk on categories (id) 

Как @symcbean пишет в комментариях, в catitems и themeitems индексы должны, вероятно, уникальные индексы тоже - если нет другого столбца, чтобы добавить к этому индексу (например, «validityDate»), добавьте это в инструкцию create.

+0

Не предполагается изменять структуру базы данных вообще. Есть ли обратная связь с этим, поэтому я могу проверить ее с помощью и без? – Michael

+0

@ Майкл, добавляющий индекс, не изменяет структуру, он не делает различий в полях и структуре таблицы, просто хранит информацию каждой записи отдельно, так же, как и в индексе книги. содержание книги остается таким же, если присутствует индекс или нет. [Технически это просто изменяет способ хранения даты, но вы можете игнорировать его на данный момент]. –

+0

Не уверен, что я понимаю ваш вопрос –

0

Ive сделал ответ выключить это, потому что я не мог поместить его в качестве комментария

Основного пальца от действия, если вы хотите, чтобы удалить полное сканирование таблицы с JOINS. Сначала вы должны указать.

Примечание что это не всегда работает с ORDER BY/GROUP BY в сочетании с JOINS, поскольку часто используется временное; используя filesort.

Extra, потому что это из вне рамки от вопроса и как исправить медленный запрос с ORDER BY/GROUP BY в сочетании с JOIN

Поскольку оптимизатор MySQL считает, что нужно, чтобы получить доступ наименьшую таблицу первой чтобы получить наилучшее выполнение, что приведет к тому, что MySQL не всегда будет использовать индексы для сортировки результата и должен использовать временную таблицу, а filesort - исправление неправильного порядка сортировки

(подробнее об этом здесь MySQL slow query using filesort вот как я исправить это проблема, потому что использование временных действительно может убить производительность, когда MySQL нуждается в временной таблице на диске)

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