MySQL: пересечение SELECT

12
sidorka
На сайте с 17.08.2012
Offline
211
6118

Как средствами MySQL найти пересечение или разницу двух SELECT?

SELECT id FROM table1

SELECT id FROM table2

Таблицы по несколько миллионов записей. Прямо использовать WHERE id NOT IN не выходит.

Пока в голову приходит только array_diff в php использовать.

Есть еще варианты?

Дешевые домены для дорвеев и не только - от 55р (https://goo.gl/Wtnwqp)
A
На сайте с 19.07.2010
Offline
130
#1

попробуйте так, может и прокатит..


SELECT t1.id FROM table1 t1, table2 t2
WHERE t1.id=t2.id

индексы по полю id должны быть на обоих таблицах.

если не прокатит, то можно тупо и в лоб за несколько итераций, меняя диапазон отбора


SELECT t1.id FROM table1 t1, table2 t2
WHERE t1.id<1000000 and t1.id=t2.id


---------- Добавлено 20.03.2016 в 11:22 ----------

sidorka:
Прямо использовать WHERE id NOT IN не выходит.

эээ... пересечение - это WHERE t1.id=t2.id, в Вашем условии - дополнение (кажись так это называется).

.............
bay_ebook
На сайте с 28.05.2010
Offline
111
#2

Нужно потестить, я так навскидку, но думаю join должен работать

SELECT table1.id FROM table1 JOIN table2 ON table2.id = table1.id

и разница

SELECT table1.id, table2.id FROM table1 FULL OUTER JOIN table2 ON table2.id <> table1.id

но я не уверен .что второй запрос будет работать.

Нужен прогер на php+mysql+понимание чужего кода? (/ru/forum/540660) Вам сюда PHP-шаман (http://php-shaman.pw/)
A
На сайте с 19.07.2010
Offline
130
#3
bay_ebook:
и разница

насколько я помню, не равенство медленно работает.

вспомнил еще рабочий финт ушами с левым джойном :)

SELECT t1.id

FROM table1 t1 left join table2 t2 on (t1.id=t2.id)
WHERE t2.id IS NULL

запрос выдаст id из первой таблицы, которых нет во второй.

переставив таблицы местами можно получить id из второй таблицы, которых нет в первой.

sidorka
На сайте с 17.08.2012
Offline
211
#4

Попробовал с джоинами.

SELECT k.id

FROM keywords AS k
LEFT OUTER JOIN (SELECT keyword_id FROM pages_1 WHERE category_id = 1) AS p
ON k.id = p.keyword_id
WHERE p.keyword_id IS NULL AND k.category_id = 1

Выборка от 15 до 45 секунд, в зависимости от текушей нагрузки сервака.

Вариант на той же базе с теми же условиями

t1 = SELECT id FROM keywords WHERE category_id = 1

t2 = SELECT keyword_id FROM pages_1 WHERE category_id = 1
php array_diff(t1, t2)

укладывается в 1-3 секунды.

Есть какие варианты ускорить запрос с джоинами?

edogs software
На сайте с 15.12.2005
Offline
775
#5

sidorka,

Покажите структуру таблиц с ключами.

И уточните задачу, в первом посте у Вас просто найти пересечение, а потом Вы добавляете условие category_id - задачи несколько разные

Ваш вариант в 5 посте - заведомо трэш в меру избыточного вложенности запроса.

В общем случае запрос

select distinct(a.id) from table1 a left join table2 b on a.id=b.id where b.id is not null

должен работать быстро, при условии наличия ключей на id и если поля id полностью одинакового типа.

Если нужно добавить id категории, то правильнее так

select distinct(a.id) from table1 a left join table2 b on a.id=b.id and a.category_id=b.category_id and a.category_id=1 and b.category_id=1 where b.id is not null

Разумеется - ключи на category_id тоже должны быть и должны быть полностью одинаковые по типу тоже.

Частая ошибка с ключами - int(11) и int(10) или int и bigint - разные вещи и скукоживаются сильно хуже.

p.s.: Можно так же попробовать добавить к обоим запросам group by a.id в конце - может сказаться сильно положительно на результате.

Разработка крупных и средних проектов. Можно с криптой. Разумные цены. Хорошее качество. Адекватный подход. Продаем lenovo legion в спб, дешевле магазинов, новые, запечатанные. Есть разные. skype: edogssoft
KOROLEV
На сайте с 10.04.2009
Offline
78
#6
sidorka:
Попробовал с джоинами.
SELECT k.id

FROM keywords AS k
LEFT OUTER JOIN (SELECT keyword_id FROM pages_1 WHERE category_id = 1) AS p
ON k.id = p.keyword_id
WHERE p.keyword_id IS NULL AND k.category_id = 1

Выборка от 15 до 45 секунд, в зависимости от текушей нагрузки сервака.

Есть какие варианты ускорить запрос с джоинами?

Так нафига джойните вложенный селект то?

у вас должно в таблице keywords быть поле равное полю идентификатора секции.

Вы смешали и кашу и мед и еще кое что.

Опишите конкретно что надо и покажите поля связанные с запросом

sidorka
На сайте с 17.08.2012
Offline
211
#7

Требуется из таблицы keywords выбрать записи в нужной категории, которых нет в таблице pages с этой же категорией. Но это просто более частный случай нахождения пересечения - ограничение выборки.

По структуре таблиц

keywords - id - int(11), category_id - int(11) и другие к запросу не относящиеся и в выборку не попадающие. Индексы - первичный id и индекс category_id.

pages - id - int(11), category_id - int(11), keyword_id - int(11) и другие к запросу не относящиеся и в выборку не попадающие. Индексы - первичный id, составной уникальный (category_id,keyword_id)

Проверил вариант такой на основе предложенного - очень долго, не дождался ответа, прибил процесс руками после третьей минуты.

SELECT k.id
FROM keywords AS k
LEFT JOIN pages_1 AS p
ON k.id = p.keyword_id
WHERE k.category_id = 1 AND p.keyword_id IS NULL


---------- Добавлено 20.03.2016 в 16:59 ----------

Запрос с вложенным селектом показывает стабильно 10-15 секунд.

Попробовал еще один вложить селект - результат тот же. Прироста не дало

SELECT k.id
FROM (SELECT id FROM keywords WHERE category_id = 1) AS k
LEFT OUTER JOIN (SELECT keyword_id FROM pages_1 WHERE category_id = 1) AS p
ON k.id = p.keyword_id
WHERE p.keyword_id IS NULL


---------- Добавлено 20.03.2016 в 17:03 ----------

Если ограничить первый запрос без вложенного подзапроса лимитами, то выборка 10к проходит за 40-50 сек, что не гуд и все равно мало.

---------- Добавлено 20.03.2016 в 17:23 ----------

edogs, второй вариант, предложенный вами, не прошел - 89970 rows in set (6 min 22.64 sec).

SELECT k.id
FROM keywords AS k
LEFT JOIN pages_1 AS p
ON k.id = p.keyword_id AND k.category_id = p.category_id AND k.category_id = 1 AND p.category_id = 1
WHERE p.keyword_id IS NULL

а вот такой выдает пустой результат

SELECT k.id
FROM keywords AS k
LEFT JOIN pages_1 AS p
ON k.id = p.keyword_id AND k.category_id = p.category_id
WHERE p.keyword_id IS NULL AND k.category_id = 1 AND p.category_id = 1

этот тоже пустой

SELECT k.id
FROM keywords AS k
LEFT JOIN pages_1 AS p
ON k.id = p.keyword_id
WHERE p.keyword_id IS NULL AND k.category_id = 1 AND p.category_id = 1


---------- Добавлено 20.03.2016 в 17:26 ----------

edogs:
Ваш вариант в 5 посте - заведомо трэш в меру избыточного вложенности запроса.

этот вариант пока единственный условно пригодный

edogs software
На сайте с 15.12.2005
Offline
775
#8

sidorka,

Посмотрите на свои запросы.

Вы пишите is null, а не is not null.

Таким образом ищете не пересечение, а как раз наоборот - записи которые есть в первой таблице и которых нет во второй.

Разница - не только в результате (который в Вашей версии неверен), но и в скорости (найти отсутствующие записи сложнее чем пересекающиеся и там другой способ нужен).

sidorka
На сайте с 17.08.2012
Offline
211
#9

edogs, на данный момент именно это и нужно - найти разницу между выборкой 1 и выборкой 2.

sidorka:
Требуется из таблицы keywords выбрать записи в нужной категории, которых нет в таблице pages с этой же категорией.

С совпадением двух выборок проще выходит, это я уже осилил.

edogs software
На сайте с 15.12.2005
Offline
775
#10
sidorka:
edogs, на данный момент именно это и нужно - найти разницу между выборкой 1 и выборкой 2.

Ок, но все же не надо использовать запрос который мы писали для для пересечения напрямую для поиска разницы. Это разные вещи в принципе.

sidorka:
Требуется из таблицы keywords выбрать записи в нужной категории, которых нет в таблице pages с этой же категорией.

Попробуйте примерно так

select a.id from keywords as a where a.cat=1 and a.id not in ( select distinct(b.keyid) from pages as b where b.cat=1 )

12

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий