仅在父查询的结果上运行子查询

时间:2013-02-08 18:35:44

标签: mysql optimization sum subquery match

我正在为收集与查询匹配的element的网站运行搜索查询。但是,可能有一个或多个items链接到element。所以,我有一个子查询,用于计算与items相关联的所有element的匹配。

此查询确实有效。但令人难以置信的慢。现在我需要大约50秒。如果我抛弃子查询,它会更快,更快。

SELECT DISTINCT e.id, 
    MATCH (e.heading) AGAINST ('+(room)') AS h_score, 
    MATCH (e.text) AGAINST ('+(room)') AS t_score, 
    ( 
        SELECT SUM( MATCH (item.heading, item.text) AGAINST ('+(room)') ) AS itemscore 
             FROM item LEFT JOIN _element_item ON item.id = _element_item.item_id 
             WHERE _element_item.item_id = e.id 
             AND MATCH (item.heading, item.text) AGAINST ('+(room)')
    ) AS i_score 

    FROM element AS e 
    LEFT JOIN _element_brand ON e.id = _element_brand.element_id 
    LEFT JOIN _element_language ON e.id = _element_language.element_id 
    LEFT JOIN _element_region ON e.id = _element_region.element_id 
    LEFT JOIN _element_type ON e.id = _element_type.element_id 
    LEFT JOIN _element_group ON e.id = _element_group.element_id     

    WHERE _element_brand.brand_id = 1 
    AND _element_language.language_iso = 'en' 
    AND _element_region.region_id = 1 
    AND _element_type.type_id = 1 
    AND _element_group.group_id = 1 
    AND e.replacement_id IS NULL 
    AND e.status = 1 
    AND MATCH (e.heading, e.text) AGAINST ('+(room)') 
    ORDER BY t_score + h_score DESC LIMIT 100

有没有办法让它跑得更快?

我猜测它在匹配element之前为每个element运行完整的子查询?我可以让它只在父查询中的匹配项上运行子查询吗?如果是这样,怎么样?

1 个答案:

答案 0 :(得分:0)

让我试着澄清你的示例场景的左连接。

select e.heading
   FROM element AS e
           LEFT JOIN _element_brand 
              ON e.id = _element_brand.element_id 
   WHERE 
          e.SomeColumn = 'test'
      AND _element_brand.brand_id = 1 

相同
select e.heading
   FROM element AS e
           JOIN _element_brand 
              ON e.id = _element_brand.element_id 
   WHERE 
          e.SomeColumn = 'test'
      AND _element_brand.brand_id = 1 

因为WHERE子句FORCING只返回具有匹配的_element_brand记录且记录的brand_id = 1的记录。因此,这将只返回“e.SomeColumn ='test'”和brand_id = 1的记录。

现在,看一下真正的左连接

select e.heading
   FROM element AS e
           LEFT JOIN _element_brand 
              ON e.id = _element_brand.element_id 
             AND _element_brand.brand_id = 1 
   WHERE 
      e.SomeColumn = 'test'

这将返回元素中包含“e.SomeColumn ='test'”的所有记录,无论_element_Brand表中是否有条目,_element_brand.brand_id = 1。

因此,如果你有100个带有SomeColumn ='test'的元素,那么50个记录在_element_brand表中有相应ID的有效记录。在这50个中,只有20个具体品牌为brand_id = 1 ......

前两个示例查询(与WHERE的左连接和连接)将仅返回20条特别具有20条记录的记录。

LAST查询仍会返回100条基于“test”验证的记录。

希望这可以澄清是否基于您的数据场景...有时在书籍或文档中看到可能实际上并未澄清某人试图掌握它。

SELECT DISTINCT 
      STRAIGHT_JOIN
      e.id, 
      MATCH (e.heading) AGAINST ('+(room)') AS h_score, 
      MATCH (e.text) AGAINST ('+(room)') AS t_score, 
      ( SELECT SUM( MATCH (item.heading, item.text) AGAINST ('+(room)') ) 
           FROM _element_item
              JOIN item 
                 ON _element_item.item_id = item.id  
                AND MATCH (item.heading, item.text) AGAINST ('+(room)')
           WHERE 
              e.id = _element_item.item_id ) AS i_score 
   FROM 
      element AS e 
         JOIN _element_brand 
            ON e.id = _element_brand.element_id 
            AND _element_brand.brand_id = 1 

         JOIN _element_language 
            ON e.id = _element_language.element_id 
            AND _element_language.language_iso = 'en' 

         JOIN _element_region 
            ON e.id = _element_region.element_id 
           AND _element_region.region_id = 1 

         JOIN _element_type 
           ON e.id = _element_type.element_id 
          AND _element_type.type_id = 1 

         JOIN _element_group ON e.id = _element_group.element_id     
          AND _element_group.group_id = 1 
   WHERE 
          e.status = 1 
      and e.replacement_id IS NULL 
      AND MATCH (e.heading, e.text) AGAINST ('+(room)') 
   ORDER BY 
      t_score + h_score DESC 
   LIMIT 100

我已经重组了加入。此外,稍微更改了i_score的字段选择sum(),似乎正在查杀您的查询。我还在顶部添加了关键字“STRAIGHT_JOIN”,告诉查询按顺序运行。

我对该字段的唯一审核问题选择...您正在加入

e.id到_element_item.item_id,然后从_element_item.item_id到item.id ....

所以,那说,可能会简化

e.id = item.id你可以完全删除_element_item表,如果它们真的相同,但它似乎是一个桥表,对于给定的元素可能有很多项。