我正在努力(再次)讨论这个问题的表:how to optimize this query (4 mm tables involved)
这是一个主表product_table
,它通过查找表mm1
到mm4
有四个MM关系。查找表的字段uid_local
包含product_table
和uid_foreign
的uid,其中包含过滤结果的类别的uid。
Quassnois根据上述问题提出改进性能后,查询如下:
SELECT
COUNT(*)
FROM
product_table
WHERE
(product_table.partner_id = 0 OR product_table.partner_id = 15) AND
EXISTS(SELECT NULL FROM mm1 WHERE mm1.uid_local = product_table.uid AND mm1.uid_foreign IN (10, 11, 12, 13, 14, 53)) AND
EXISTS(SELECT NULL FROM mm2 WHERE mm2.uid_local = product_table.uid AND mm2.uid_foreign IN (7, 8, 9)) AND
EXISTS(SELECT NULL FROM mm3 WHERE mm3.uid_local = product_table.uid AND mm3.uid_foreign IN (51 ,52)) AND
EXISTS(SELECT NULL FROM mm4 WHERE mm4.uid_local = product_table.uid AND mm4.uid_foreign IN (15, 16, 17, 18, 19))
这会在COUNT(*)
之间返回大约10.000行,但需要>查询执行时间为0.5秒。这太慢了。
EXPLAIN
看起来像这样:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY product_table ref NewIndex NewIndex 4 const 9430 Using where
5 DEPENDENT SUBQUERY mm1 ref uid_local,uid_foreign uid_local 4 mm1.uid 5 Using where
4 DEPENDENT SUBQUERY mm2 ref uid_local,uid_foreign uid_local 4 mm2.uid 2 Using where
3 DEPENDENT SUBQUERY mm3 ref uid_local,uid_foreign uid_local 4 mm3.uid 3 Using where
2 DEPENDENT SUBQUERY mm4 ref uid_local,uid_foreign uid_local 4 mm4.uid 6 Using where
如果我将product_table.partner_id = 0
更改为返回较少行的内容e。 G。几百左右的查询非常快(0.015秒)。
所以问题是,如果COUNT(*)
查询只需要计算几行(100 - 200),但计算更大的结果集(> 10.000行)非常慢,那么uid_local
查询速度非常快。
有关如何解决此问题的任何想法?
一些事实:
uid_foreign
和product_table
partner_id
有一个索引PK,product_table
IN
表包含大约30.000行修改
IN (7, 8, 9)
条款未已修复,查询可能不是IN (7, 9)
,而是{{1}}或其他数字组合。
答案 0 :(得分:0)
您可以对查询的EXISTS部分使用实体化视图。这样,您可以将IN
语句折叠为单个查询。然后你只需要在uid
上创建一个索引,查询几乎不需要时间了:
SELECT
COUNT(*)
FROM
product_table
WHERE
(product_table.partner_id = 0 OR product_table.partner_id = 15) AND
EXISTS(SELECT NULL FROM vmm1 WHERE vmm1.uid_local = product_table.uid) AND
EXISTS(SELECT NULL FROM vmm2 WHERE vmm2.uid_local = product_table.uid) AND
EXISTS(SELECT NULL FROM vmm3 WHERE vmm3.uid_local = product_table.uid) AND
EXISTS(SELECT NULL FROM vmm4 WHERE vmm4.uid_local = product_table.uid)
缺点:如果你经常更改mm表,那么视图将需要更新,这将使这些表的更改变慢。
答案 1 :(得分:0)
在mysql手册中查看FORCE INDEX。如果你的M2M表中有10k行匹配,优化器可能已经决定扫描表比查询索引更好,但在你的情况下,可能不是。