как оптимизировать этот запрос (4 мм таблицы) - PullRequest
2 голосов
/ 12 октября 2009

Я работаю со старой схемой базы данных, которая выглядит следующим образом:

product_table таблица содержит поля:

uid (int, первичный ключ)
name (varchar 50)


category таблица содержит поля:

uid (int, первичный ключ)
name (Варчар 50)

<ч />

Хорошо, теперь product_table имеет 4 ММ отношения с таблицей категорий:

product_table__category_1__mm имеет поля:

uid_local (int, содержит product_table.uid)
uid_foreign (int, содержит category.uid)


product_table__category_2__mm имеет поля:

uid_local (int, содержит product_table.uid)
uid_foreign (int, содержит category.uid)


product_table__category_3__mm имеет поля:

uid_local (int, содержит product_table.uid)
uid_foreign (int, содержит category.uid)


product_table__category_4__mm имеет поля:

uid_local (int, содержит product_table.uid)
uid_foreign (int, содержит category.uid)

(да, все таблицы 4 ММ имеют одинаковые поля и все относятся к таблице category)

<ч />

Итак, если я хочу получить все четыре соединения и отфильтровать их по значениям int, выбранным пользователем, это будет выглядеть примерно так:

select
product_table.*

from
product_table

inner join product_table__category_1__mm mm_1 on mm_1.uid_local = product_table.uid
inner join category cat_1 on cat_1.uid = mm_1.uid_foreign and cat_1.uid in (7, 8)

inner join product_table__category_2__mm mm_2 on mm_2.uid_local = product_table.uid
inner join category cat_2 on cat_2.uid = mm_2.uid_foreign and cat_2.uid in (63, 52)

inner join product_table__category_3__mm mm_3 on mm_3.uid_local = product_table.uid
inner join category cat_3 on cat_3.uid = mm_3.uid_foreign and cat_3.uid in (84, 12)

inner join product_table__category_4__mm mm_4 on mm_4.uid_local = product_table.uid
inner join category cat_4 on cat_4.uid = mm_4.uid_foreign and cat_4.uid in (16, 33)

group by product_table.uid ### --> in order to get unique results

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

Есть идеи, как сделать этот запрос быстрее? Где бы вы положили индексы?

Ответы [ 3 ]

0 голосов
/ 12 октября 2009

Ну, оба поля в таблицах "mm" должны быть проиндексированы, как и поле uid в таблице продуктов и uid в таблице категорий. Но я думаю, что все эти поля уже проиндексированы.

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

0 голосов
/ 12 октября 2009

Вы должны избавиться от GROUP BY здесь.

MySQL не подходит для его оптимизации.

Перепишите ваш запрос следующим образом:

SELECT  *
FROM    product_table
WHERE   EXISTS
        (
        SELECT  NULL
        FROM    product_table__category_1__mm mm_1
        JOIN    category cat_1
        ON      cat_1.uid = mm_1.uid_foreign
        WHERE   mm_1.uid_local = product_table.uid
                AND mm_1.uid_foreign IN (7, 8)
        )
        AND
        …        

Создание индексов:

product_table__category_*__mm (uid_local, uid_foreign)

или, лучше, объявить их PRIMARY KEYs на product_table__category_*__mm:

ALTER TABLE product_table__category_*__mm ADD CONSTRAINT pk_pc*mm_local_foreign (uid_local, uid_foreign)
0 голосов
/ 12 октября 2009

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

  1. Разбейте его на более мелкие запросы, использующие только таблицы, необходимые для определенных операций,

  2. Используйте Select field1, field2 .etc вместо Select *, указав только поля, необходимые для определенных операций, и

  3. Убедитесь, что все первичные и внешние ключи имеют индексы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...