Производительность MySQL, внутреннее соединение, как избежать использования временных и файловой сортировки - PullRequest
3 голосов
/ 26 июля 2010

У меня есть таблица 1 и таблица 2.

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

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

Таблица 1 содержит 1 миллион записей, а таблица 2 содержит 1000 записей.

Я пытаюсь оптимизировать какой-то запрос с помощью 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 показывает временную + файловую сортировку в плане выполнения. Как я могу избежать этого?

"ЗЛО" в ЗАКАЗАТЬ на pb.brand ASC . Упорядочение по этому внешнему полю кажется узким местом ..

Ответы [ 4 ]

1 голос
/ 28 июля 2010

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

0 голосов
/ 08 августа 2012

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

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 AND tmp_table_size установлены вчисло, достаточно большое для хранения результатов:

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

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

0 голосов
/ 28 июля 2010

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

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

Тем не менее, комбинация external-join, order-by и limit заставляет меня задуматься, что именно вызапрашивают, и если не может быть лучшего способа выразить сам запрос.

0 голосов
/ 26 июля 2010

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

ALTER TABLE products_brands ADD INDEX newIdx (brand_name, id_brand)

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

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

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

...