我有两个运行速度非常快的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工作台来查看执行计划,但它显示“解释数据不可用于语句”
如果您看到我可以改进或尝试的任何内容,请告诉我。谢谢。
答案 0 :(得分:3)
IN ( SELECT ... )
的优化程度很低,至少在旧版本的MySQL中是这样。你用的是哪个版本?
使用FULLTEXT
索引(MATCH...
)时,如果可能,首先执行该部分。这是因为几乎总是FT查找比其他任何事情都要快。
但是当使用两个全文查询时,它会选择一个,然后不能在另一个上使用全文。
以下是一种可能的解决方法:
Name
和Locations
。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
表,而不是将位置存储在表中的列表中。