(MySQL) Поиск наиболее оптимального решения.
От: MasterMind Россия  
Дата: 07.03.16 14:51
Оценка:
Есть две таблицы.

Таблица 1. Список какого то контента

mysql> desc contents;
+------------------+----------------------+------+-----+---------+----------------+
| Field            | Type                 | Null | Key | Default | Extra          |
+------------------+----------------------+------+-----+---------+----------------+
| id               | int(10) unsigned     | NO   | PRI | NULL    | auto_increment |
| title            | varchar(255)         | NO   |     | NULL    |                |
+------------------+----------------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)



Tаблица 2. Список контента который не нужно отображать.

mysql> desc content_skip;
+-----------------+----------------------+------+-----+-------------------+----------------+
| Field           | Type                 | Null | Key | Default           | Extra          |
+-----------------+----------------------+------+-----+-------------------+----------------+
| id              | int(11)              | NO   | PRI | NULL              | auto_increment |
| content_id      | int(11)              | YES  |     | 0                 |                |
+-----------------+----------------------+------+-----+-------------------+----------------+
2 rows in set (0.00 sec)


Суть вопроса в следующем:

Нужно вернуть данные из Таблица 1 такие, которые не входят в таблицу Tаблица 2. Соответственно, есть два решения.

1.
 select id from contents where id not in (select content_id from content_skip)


2. Выбрать сразу все id content_skip и потом в перечислении добавить.

 select id from contents where id not in (3,4,5)



Первый запрос не нравится DEPENDENT SUBQUERY, а второй тем, что этих id может быть очень большая куча, что в итоге превысит размер пакета запроса.
Вопрос, что можно еще придумать наиболее?
Re: (MySQL) Поиск наиболее оптимального решения.
От: Иль  
Дата: 07.03.16 18:56
Оценка: 4 (1) +1
Здравствуйте, MasterMind, Вы писали:

MM>Есть две таблицы.

MM>Нужно вернуть данные из Таблица 1 такие, которые не входят в таблицу Tаблица 2.
Специально для таких случаев существует конструкция NOT EXISTS:

SELECT id 
FROM contents c 
WHERE NOT EXISTS (
    SELECT 1 
    FROM content_skip cs 
    WHERE cs.content_id = c.id
)


СУБД должна оптимизировать такие запросы. Если у неё это не получится, то увы, навряд ли получится переизобрести что-либо оптимальнее.
Отредактировано 07.03.2016 19:00 Иль . Предыдущая версия .
Re[2]: (MySQL) Поиск наиболее оптимального решения.
От: wildwind Россия  
Дата: 07.03.16 19:17
Оценка: 4 (1)
Здравствуйте, Иль, Вы писали:

Иль>СУБД должна оптимизировать такие запросы. Если у неё это не получится,


Если не получится, то можно сделать OUTER JOIN.
Re: (MySQL) Поиск наиболее оптимального решения.
От: anovokreschenov Россия  
Дата: 07.03.16 20:19
Оценка: 4 (1) +1
NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL
Re: (MySQL) Поиск наиболее оптимального решения.
От: MasterZiv СССР  
Дата: 18.03.16 17:10
Оценка:
Здравствуйте, MasterMind, Вы писали:


MM>Нужно вернуть данные из Таблица 1 такие, которые не входят в таблицу Tаблица 2. Соответственно, есть два решения.


MM>1.

MM>
MM> select id from contents where id not in (select content_id from content_skip)
MM>


MM>2. Выбрать сразу все id content_skip и потом в перечислении добавить.


MM>
MM> select id from contents where id not in (3,4,5)
MM>



MM>Первый запрос не нравится DEPENDENT SUBQUERY, а второй тем, что этих id может быть очень большая куча, что в итоге превысит размер пакета запроса.

MM>Вопрос, что можно еще придумать наиболее?

Есть только одно решение, и оно у тебя под номером 1
(ещё есть вариант с коррелированным подзапросом, вводимым NOT EXISTS и с LEFT JOIN и фильтром на отрицательный результат JOIN-а в WHERE,
но это по сути одно и то же -- реализация реляционного вычитания).

Нравится тебе этот вариант или нет -- значения не имеет, потому что другого варианта нет.
И да, этот единственный вариант сложен в смысле вычислительных затрат, не потому, что DEPENDENT SUBQUERY, а потому,
что нужно проверять все сочетания строк из двух таблиц, при наличии индекса (а это очень сильно упростит задачу) --
все строки из внешней таблицы * log( кол-ва строк из внутренней ).

Есть особенности и именно MySQL в этом аспекте, говорят, что некоторые версии оптимизатора в случае с IN материализуют
подзапрос, что плохо. Так что рекомендую проверить план перед выполнением и убедится, что он хороший. (не квадратичный)
Если IN не покатит, замени на NOT EXIST.

Ну и создавай индексы в обоих таблицах по этому ID, если их ещё нет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.