MySQL优化的联接查询,条件为“ OR”

时间:2018-07-06 14:49:38

标签: mysql sql optimization entity-attribute-value

我有一个数据库,其中包含50万个公司简介及其提供服务的位置。 所以我有公司表+位置表。 公司可以在全国范围内或仅在一个城市中提供服务。 位置表如下所示:

ID | company_id       | scope     | country_id | city_id
1  | 'companyuuid...' | 'city'    | 'UK'       | '32321'
2  | 'companyuuid...' | 'country' | 'US'       | NULL

当公司在全国范围内提供服务时,我们将范围“国家”标明,而当公司仅在特定城市内提供服务时,我们将范围“城市”标明。

不幸的是,当MySQL具有“ OR”语句并考虑到需要处理的数据量时,MySQL处理查询的速度会非常慢。

select distinct companies.id from companies

inner join locations on companies.id = locations.company_id
and (locations.scope = 'city' and locations.city_id = '703448' ) 

order by companies.score desc limit 12 offset 0

我当前的问题是,在城市中寻找公司时,我还需要展示在全国范围内提供服务的公司。显而易见的方法是添加如下的OR语句:

select distinct companies.id from companies

inner join locations on companies.id = locations.company_id
and (locations.scope = 'city' and locations.city_id = '703448' ) 
or (locations.scope = 'country' and locations.country_id = 'UK' ) 
order by companies.score desc limit 12 offset 0

但是问题是OR语句会使查询非常慢。 也许还有其他使用附加联接的方法,这样我们可以使查询保持快速吗?

2 个答案:

答案 0 :(得分:0)

我建议使用exists

select c.id
from companies c
where exists (select 1
              from locations l
              where l.company_id = c.id and
                    l.scope = 'city' and
                    l.city_id = 703448  -- I'm guessing city_id is a number, so no quotes
             ) or
      exists (select 1
              from locations l
              where l.company_id = c.id and l.scope = 'country'
             )
order by c.score desc
limit 12 offset 0;

exists子查询可以利用locations(company_id, scope, city_id)上的索引。该查询甚至可以利用companies(score)上的索引。

答案 1 :(得分:0)

问题1:OR似乎是“错误的”。您要英国的所有城市,再加上伦敦的所有城市,包括加拿大的所有城市吗?

您可能希望使用AND而不是OR。您将需要“自我加入”才能两次进入locations? EAV模式糟透了。

问题2:x AND y OR z(x AND y) OR z,而不是x AND (y OR z)