MySQL оптимизированный запрос соединения с условием «ИЛИ»

0

У меня есть база данных с 500 тыс. Профилей компаний + места, где они предоставляют свои услуги. Таким образом, у меня есть таблица таблиц таблиц компаний. Компания может обслуживать всю страну или только в городе. Таблица мест выглядит следующим образом:

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

Когда компания предоставляет услуги по всей стране, мы указываем сферу действия "страна", и у нас есть область "город", когда компания предоставляет услуги только в определенном городе.

К сожалению, MySQL довольно медленно обрабатывает запросы, когда у них есть оператор "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' ) 

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 сделает запрос чрезвычайно медленным. Есть ли другой способ использовать дополнительное соединение, возможно, поэтому мы можем быстро сохранить запрос?

  • 0
    Вы можете разбить запросы и использовать union вместо or
Теги:
optimization
entity-attribute-value

2 ответа

0

Проблема 1: OR кажется "неправильной". Вы хотите, чтобы все города в Великобритании, а также все Лондоны, в том числе и в Канаде.

Вы, вероятно, хотите AND вместо OR. И вам понадобится "самостоятельное соединение", чтобы дважды попасть в locations? Схема EAV сосет.

Задача 2: x AND y OR z (x AND y) OR z, а не x AND (y OR z).

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).

  • 0
    Спасибо. Я только что проверил это. Это работает хорошо, но это не решает мою проблему, к сожалению. Этот запрос занимает 3,8 секунды, а при использовании запроса «соединение» - всего 6 мс.
  • 0
    @NickSurmanidze. , , join с or занимает всего 6 мс? Это поразительно. У вас есть рекомендуемые join для этого запроса?
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню