没有结果时查询工作太慢。怎么改进呢?

时间:2012-03-22 09:46:09

标签: mysql query-optimization

我有三张桌子

filters (id, name)
items(item_id, name)
items_filters(item_id, filter_id, value_id)
values(id, filter_id, filter_value)

项目中约有20000个条目。 items_filters中约有80000个条目。

SELECT i.*
    FROM items_filters itf INNER JOIN items i ON i.item_id = itf.item_id
     WHERE (itf.filter_id = 1 AND itf.value_id = '1') 
     OR (itf.filter_id = 2 AND itf.value_id = '7') 
    GROUP BY itf.item_id 
    WITH ROLLUP 
    HAVING COUNT(*) = 2
   LIMIT 0,10;

当条目匹配查询时为0.008时,没有条目匹配时为0.05。

之前我尝试过不同的变体:

SELECT * FROM items WHERE item_id IN (
    SELECT `item_id` 
     FROM `items_filters` 
     WHERE (`filter_id`='1' AND `value_id`=1) 
     OR (`filter_id`='2' AND `value_id`=7)
    GROUP BY `item_id` 
    HAVING COUNT(*) = 2
   ) LIMIT 0,6;

当没有条目时,这会完全冻结mysql。

我真的没有得到的是     选择我。*     FROM items_filters itf INNER JOIN items i ON i.item_id = itf.item_id      WHERE itf.filter_id = 1 AND itf.value_id ='1'LIMIT 0,1 没有条目时需要〜0.05,

时需要~0.008

解释

| id | select_type | table | type | possible_keys | key     | key_len | ref                 | rows | Extra                           |
|  1 | SIMPLE      | i     | ALL  | PRIMARY       | NULL    | NULL    | NULL                |   10 | Using temporary; Using filesort |
|  1 | SIMPLE      | itf   | ref  | item_id       | item_id | 4       | ss_stylet.i.item_id |    1 | Using where; Using index        |

2 个答案:

答案 0 :(得分:0)

对我来说,这看起来像是四张桌子。

对查询执行EXPLAIN PLAN并查找TABLE SCAN。如果您看到一个,请在WHERE子句中的列上添加索引。那些肯定会有所帮助。

答案 1 :(得分:0)

除了对两个上的items_filters进行确认和索引(filter_id,value_id)之外,我还会预先通过分组对您的项目ID进行资格预审,然后加入项目表。看起来您正在尝试找到满足两个特定条件的项目,对于那些,请抓住项目......

我还在外部留下了“with by with rollup”,即使内部查询返回的每个ID都有一个实例。但由于内部查询已经应用了0,10条记录的限制,因此不会将过多的结果加入到您的项目表中。

但是,由于您没有进行任何聚合,我相信外部的group by和rollup并不会真正为您提供任何好处,否则可能会被删除。

SELECT i.*
   FROM
      ( select itf.item_id
           from items_filters itf
          WHERE (itf.filter_id = 1 AND itf.value_id = '1') 
             OR (itf.filter_id = 2 AND itf.value_id = '7') 
          GROUP BY itf.item_id 
          HAVING COUNT(*) = 2
          LIMIT 0, 10 ) PreQualified
      JOIN items i 
         ON  PreQualified.item_id = i.item_id

另一种方法可能是在内部查询上进行JOIN,因此您甚至不需要应用组和拥有。由于您明确要查找两个项目,我会尝试以下内容。这样,第一个限定符就是它必须有一个ID = 1和value ='1'的条目。它甚至没有打入这个条目,它永远不会关注第二个。然后,通过将连接应用于同一个表(别名itf2),它必须在相同的ID上找到 - 和第二个的条件(id = 2 value ='7')。这基本上强制看起来几乎像单个传递对一个条目FIRST,最重要的是在考虑其他任何事情之前。在收到项目详细信息之前,这仍然会导致您的有限10套。

SELECT i.*
   FROM
      ( select itf.item_id
           from items_filters itf
              join items_filters itf2
                 on itf.item_id = itf2.item_id
                AND itf2.filter_id = 2 
                AND itf2.value_id = '7'
          WHERE 
             itf.filter_id = 1 AND itf.value_id = '1'
          LIMIT 0, 10 ) PreQualified
      JOIN items i 
         ON  PreQualified.item_id = i.item_id

我还根据你的重复评论(按照我的预期)通过/用汇总删除了这个组。