如何优化此查询(涉及4 mm表)

时间:2009-10-12 16:29:48

标签: mysql optimization

我正在使用看起来像这样的遗留数据库模式:

product_table表包含字段:

uid(int,主键)
name(varchar 50)


category表包含字段:

uid(int,主键)
name(varchar 50)


好吧,现在product_table与类别表有4个MM关系:

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个MM表都有相同的字段,都与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 :(得分:0)

在任何特定时刻,您不太可能同时需要所有这些数据。如果我错了,你可以纠正我,但如果这在任何地方被用作“主”查询,我会:

  1. 将其分解为仅使用特定操作中所需表格的较小查询,

  2. 使用Select field1,field2 .etc而不是Select *,仅指定特定操作所需的字段,

  3. 确保所有主键和外键都有索引。

答案 1 :(得分:0)

嗯,“mm”表中的两个字段都应该被编入索引,产品表上的uid字段和类别表上的uid也应该被编入索引。但我的猜测是所有这些字段都已编入索引。

为了更容易理解针对该混乱的查询,您可能还需要考虑将上面发布的查询也放到视图中。

答案 2 :(得分:0)

你需要在这里摆脱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)