使用4 MM关系和更大的表优化COUNT(*)查询

时间:2009-10-20 15:47:00

标签: mysql optimization

我正在努力(再次)讨论这个问题的表:how to optimize this query (4 mm tables involved)


这是一个主表product_table,它通过查找表mm1mm4有四个MM关系。查找表的字段uid_local包含product_tableuid_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查询速度非常快。

有关如何解决此问题的任何想法?


一些事实:

  • mm表格在uid_foreignproduct_table
  • 上有索引
  • partner_id有一个索引PK,product_table
  • 上有另一个索引
  • IN表包含大约30.000行

修改

IN (7, 8, 9)条款已修复,查询可能不是IN (7, 9),而是{{1}}或其他数字组合。

2 个答案:

答案 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行匹配,优化器可能已经决定扫描表比查询索引更好,但在你的情况下,可能不是。