2010-07-26 2 views
3

У меня есть таблица 1 и таблица 2.производительность MySQL, внутреннее соединение, как избежать использования временных и FileSort

Таблица 1 PARTNUM - ID_BRAND partnum является первичным ключом id_brand является "индексированный"

Таблица 2 iD_BRAND - BRAND_NAME id_brand является первичным ключом BRAND_NAME является "индексируется"

в таблице 1 содержится 1 млн записей и таблица 2 содержит 1.000 записей.

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

EXPLAIN 
SELECT pm.partnum, pb.brand_name 
FROM products_main AS pm 
LEFT JOIN products_brands AS pb ON pm.id_brand=pb.id_brand 
ORDER BY pb.brand ASC 
LIMIT 0, 10 

Запрос возвращает этот план выполнения:

ID, SELECT_TYPE, TABLE, TYPE, POSSIBLE_KEYS, KEY, KEY_LEN , REF, ROWS, EXTRA 
1, SIMPLE, pm, range, PRIMARY, PRIMARY, 1, , 1000000, Using where; Using temporary; Using filesort 
1, SIMPLE, pb, ref, PRIMARY, PRIMARY, 4, demo.pm.id_pbrand, 1, 

Оптимизатор запросов MySQL показывает временную + FileSort в плане исполнения. Как я могу избежать этого?

«ЗЛО» находится в ORDER BY pb.brand ASC. Заказ на это внешнее поле, по-видимому, является узким местом.

+0

Какие индексы у вас есть в этих таблицах? – eillarra

+0

Угадайте, если у вас нет индекса на pb.brand, то mysql нужно будет отсортировать все строки 1M до применения предела – StuartLC

+0

ТАБЛИЦА 1: PARTNUM - это PK, а ID_BRAND - это индекс для ускорения ТАБЛИЦА2: ID_BRAND - это PK и BRAND - это индекс для ускорения – Vincenzo

ответ

0

Сначала попробуйте изменить свой индекс на products_brands стол. Удалите существующий на brand_name, и создать новый:

ALTER TABLE products_brands ADD INDEX newIdx (brand_name, id_brand) 

Затем таблица уже есть «orderedByBrandName» индекс с идентификаторами вам нужно для объединения, и вы можете попробовать:

EXPLAIN 
SELECT pb.brand_name, pm.partnum 
FROM products_brands AS pb 
    LEFT JOIN products_main AS pm ON pb.id_brand = pm.id_brand 
LIMIT 0, 10 

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

+0

У меня есть два индекса на PRODUCT_BRANDS. Первый - на id_brand (это первичный ключ, и он имеет неявный индекс). Второй по адресу brand_name. – Vincenzo

+0

Я изменил порядок JOIN TABLES, но ничего не изменилось. Оптимизатор запросов выбирает порядок таблицы, и он не соответствует порядку SQL sintax. – Vincenzo

+0

Вы изменили индекс? Я прочитал в вашем вопросе, что у вас есть два индекса: вам нужно изменить одно на имя_маркета и сделать его (имя_маркинга, id_brand). – eillarra

0

Прежде всего, я сомневаюсь в том, что использование внешнего соединения рассматривается как порядок, действующий на rhs, и NULL, введенный левым соединением, скорее всего, будет иметь хаос с ним.

Независимо от того, самый простой способ ускорения этого запроса был бы индексом покрытия на pb.id_brand и pb.brand. Это позволит упорядочивать оценку «using index» с условием объединения. Альтернативой является поиск некоторого способа уменьшить размер промежуточного результата, переданного в порядок.

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

1

Попробуйте заменить соединение на подзапрос. Оптимизатор MySQL - отстой; подзапросы часто дают лучшую производительность, чем объединения.

+0

У вас есть источник этого ...? – jocull

+0

Я тестировал с похожим запросом, и он прав, это имело огромное значение. Перемещение ORDER BY x DESC LIMIT 20 в подзапрос удалило временное использование, а время запроса прошло от 5 секунд до 0,0017 секунды. – ColinM

+5

@ColinM как вы перемещаете 'ORDER BY x DESC LIMIT 20' в подзапрос? Возможно, вы можете опубликовать пример запроса в качестве дополнительного ответа на этот вопрос? –

0

Этот вопрос несколько устарел, но я нашел его, и так будут другие люди.

Mysql использует временные, если ORDER BY или GROUP BY содержит столбцы из таблиц, отличных от первой таблицы в очереди объединений.

Так что вам просто нужно иметь порядок соединения обращенный с помощью STRAIGHT_JOIN, чтобы обойти порядок изобретенного оптимизатора:

SELECT STRAIGHT_JOIN pm.partnum, pb.brand_name 
FROM products_brands AS pb 
RIGHT JOIN products_main AS pm ON pm.id_brand=pb.id_brand 
ORDER BY pb.brand ASC 
LIMIT 0, 10 

Также убедитесь, что max_heap_table_size И tmp_table_size переменными устанавливаются в ряд достаточно большим, чтобы сохранить Результаты:

SET global tmp_table_size=100000000; 
SET global max_heap_table_size=100000000; 

- 100 мегабайт в этом примере. Они также могут быть установлены в файле конфигурации my.cnf.

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