当组合两个非常快的查询时,MySQL慢查询

时间:2017-02-07 18:47:41

标签: mysql sql performance

我有两个运行速度非常快的MySQL查询,但是当我将它们组合起来时,新查询非常慢。

快速(<1秒,15个结果):

SELECT DISTINCT 
Id, Name, Company_Id
FROM people
where Company_Id in (5295, 1834)
and match(Locations) against('austin')

快速(<1秒,2970结果):

select distinct Company_Id from technologies
    where match(Name) against('elastic')
      and Company_Id is not null

当我将这两者合并时:

SELECT DISTINCT Id, Name, Company_Id
FROM people
where Company_Id in
    ( select Company_Id from technologies
        where match(Name) against('elastic')
          and Company_Id is not null
    )
  and match(Locations) against('austin')

结果查询需要2分钟才能完成。它有278行。

我尝试过几种方法重写慢查询。另一个例子是这样的:

SELECT DISTINCT 
`Extent1`.`Id`, `Extent1`.`Name`, `Extent1`.`Company_Id`
FROM `people` AS `Extent1` 
INNER JOIN `technologies` AS `Extent2`
     ON (`Extent1`.`Company_Id` = `Extent2`.`Company_Id`)
WHERE (`Extent1`.`Company_Id` IS NOT NULL) 
 AND ((match(`Extent1`.`Locations`) against('austin')) 
 AND  (match(`Extent2`.`Name`) against('elastic')))

我在Windows上使用MySQL 5.7。我在名称和位置列上有全文索引。我的InnoDB缓冲区使用率从未超过40%。我尝试使用MySQL工作台来查看执行计划,但它显示“解释数据不可用于语句”

如果您看到我可以改进或尝试的任何内容,请告诉我。谢谢。

2 个答案:

答案 0 :(得分:3)

IN ( SELECT ... )的优化程度很低,至少在旧版本的MySQL中是这样。你用的是哪个版本?

使用FULLTEXT索引(MATCH...)时,如果可能,首先执行该部分。这是因为几乎总是FT查找比其他任何事情都要快。

但是当使用两个全文查询时,它会选择一个,然后不能在另一个上使用全文。

以下是一种可能的解决方法:

  • 有一个额外的搜索表。它中包含NameLocations
  • FULLTEXT(Name, Locations)
  • MATCH (Name, Locations) AGAINST ('+austin +elastic' IN BOOLEAN MODE)

如果有必要,AND有一些东西可以验证它不是,例如找到一个名叫'Austin'的人。

另一种可能性:

5.7(或5.6?)可能能够通过在子查询上创建索引来优化它:

SELECT ...
    FROM ( SELECT Company_Id FROM ... MATCH(Name) ... ) AS x
    JOIN ( SELECT Company_Id FROM ... MATCH(Locations) ... ) AS y
        USING(Company_id);

提供EXPLAIN;我希望看到<auto-key>

测试一下。如果它“快”,则您可能需要添加另一个JOIN和/或WHERE。 (我不清楚你的最终查询需要是什么。)

答案 1 :(得分:2)

使用子查询在from子句中编写查询:

select distinct p.Id, p.Name, p.Company_Id
from people p join
     (select Company_Id
      from technologies
      where match(Name) against('elastic') and Company_Id is not null
     ) t
     on p.Company_Id = t.Company_Id
where match(p.Locations) against ('austin');

我怀疑您的数据结构存在问题。您应该有一个CompanyLocations表,而不是将位置存储在表中的列表中。