Оптимизация запроса MySQL с несколькими левыми соединениями
У меня есть таблицы NewsStories, которые я оставил с некоторыми связанными таблицами. Каждая новость может содержать несколько изображений, категорий и адресов. Таким образом, запрос по существу:
SELECT * FROM NewStories
LEFT JOIN Images ON Newstories.id=Images.story_id
LEFT JOIN Categories ON NewsStories.id=Categories.story_id
LEFT JOIN Addresses ON NewsStories.id=Addresses.story_id
WHERE ...
Как правило, несколько изображений и адресов для каждой истории и 1 или 2 категории. Таблица NewsStories содержит около 10 000 статей.
Проблема в том, что производительность довольно медленная (порядка 15-20 секунд, хотя она немного меняется и иногда падает до 5 секунд).
Мне было интересно, есть ли лучший способ организовать запрос для его ускорения (я довольно новичок в SQL).
В частности, кажется довольно расточительным, что количество строк для данной истории умножается на количество изображений, умноженное на количество адресов, умноженное на количество категорий.
Я по существу пытаюсь восстановить свойства новостной истории в один объект, с которым я могу манипулировать в интерфейсе.
Здесь объяснение (извинения, если форматирование не получается правильно). Я предполагаю, что я не индексирую адреса правильно, если это "Использование где". Это правильно?
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Addresses ALL NULL NULL NULL NULL 6640 Using where
1 SIMPLE NewsStories eq_ref PRIMARY PRIMARY 767 NewsStories.Addresses.story_id 1 Using where
1 SIMPLE Images ref PRIMARY PRIMARY 767 NewsStories.NewsStories.id 1 Using index
1 SIMPLE Categories ref PRIMARY PRIMARY 767 NewsStories.NewStories.id 1
Ответы
Ответ 1
- Убедитесь, что у вас есть индексы в полях, которые содержатся в ваших операторах WHERE и условиях ON, первичные ключи индексируются по умолчанию, но вы также можете создавать индексы вручную, если вам нужно.
CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name [Index_type] ON tbl_name (index_col_name,...) [Index_type]
index_col_name: col_name [(длина)] [ASC | DESC]
index_type: ИСПОЛЬЗОВАНИЕ {BTREE | HASH}
-
Проверьте, действительно ли вам нужно выбрать каждый столбец во всех таблицах? Если нет, убедитесь, что вы выбрали только нужные столбцы, не используйте select *
-
Двойная проверка, действительно ли вам нужны ЛЕВОЕ СОЕДИНЕНИЕ, если нет, используйте INNER JOINs.
-
Если производительность по-прежнему остается проблемой после того, как вы выполнили настройку своего запроса, рассмотрите возможность денормализации вашей схемы для устранения объединений
-
Вы также можете рассмотреть возможность снижения нагрузки на базу данных с помощью приложений кэширования, таких как sphinxsearch и memcached
-
Проверьте, что ни одно из ваших соединений не относится к представлениям, а не к фактическим таблицам.
ссылки:
http://www.sphinxsearch.com
http://dev.mysql.com/doc/refman/5.0/en/create-index.html
Ответ 2
Убедитесь, что ваши таблицы правильно проиндексированы. Вам нужно иметь индекс для каждого столбца, который вы используете для выбора данных, иначе MySQL будет проходить через каждую строку таблицы.
Попробуйте объяснить запрос (EXPLAIN SELECT * FROM ...etc
) в консоли MySQL, чтобы увидеть, как MySQL обрабатывает таблицы внутри. Вставьте результаты в свой вопрос для получения дополнительной справки.