main

mysql и INTERSECT

Вобщем не умеет оно его. posgre умеет, sqlite3 - умеет, а этот "стандарт вебмастера" - нет.

Исходные данные:

  • a - 500.000 записей
  • b - 100.000 записей
  • ab ~ 15.000.000 записей (соединяет по идентификатору строку из a с одним или несколькими из b)
-- пиздец, выполняется ~ 12-20 секунд, в зависимости от посторонней нагрузки.
SELECT a_id FROM ab WHERE
  b_id = (SELECT b.id FROM b WHERE b.field = <...>);

-- тоже пиздец, хотя при выполнении подзапроса будет то же самое единственное значение
SELECT a_id FROM ab WHERE
  b_id IN (SELECT b.id FROM b WHERE b.field =  <...>);

-- ...не говоря уже про
SELECT a_id FROM ab WHERE
  a_id IN (SELECT a.id FROM a WHERE <...>) AND
  b_id IN (SELECT b.id FROM b WHERE <...>);

-- а вот так норм, хотя казалось бы - объединяются 2 нехуёвые таблицы
-- и логически это должно быть эквивалентно первому запросу
-- выполняется такое в моём случае ~ 0.3 секунды
SELECT a_id FROM ab
  JOIN b ON (ab.b_id = b.id)
  WHERE <...>;

-- и даже вот такое переваривается без особых последствий
SELECT a_id FROM ab
  JOIN a ON (ab.a_id = a.id)
  JOIN b ON (ab.b_id = b.id)
  WHERE <...>; -- куча параметров

-- В интернете народ извращается так:
SELECT all.a_id,COUNT(*) as 'cnt' FROM (
  SELECT a.id as 'id' FROM a WHERE <...>
  UNION ALL
  SELECT b.id as 'id' FROM b WHERE <...>
) as 'all' GROUP BY all.a_id HAVING cnt = 2; -- по количеству запросов
-- работает оно не намного быстрее подзапросов, проверял на той же базе
-- и, если нам внезапно понадобится ещё и EXCEPT - бида-бида