powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Пересечение наборов (списков) на уровне SQL-запроса
20 сообщений из 20, страница 1 из 1
Пересечение наборов (списков) на уровне SQL-запроса
    #39010816
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Есть 2 запроса, каждый из которых возвращает множество идентификаторов (по 3000 штук)
Нужно найти их пересечение.

Просто-напросто эти 2 запроса я вначале объединял через INNER JOIN как положено с использованием индексов. Такой запрос выполняется не очень быстро. Все варианты с разными индексами и разными комбинациями условий испробовал - результат не устраивает.

В то же время каждый из подзапросов отдельно выполняется в 10 раз быстрее. Вот и хочу последовательно их выполнить и найти пересечение. Можно это сделать и на уровне php, но на уровне MySQL должно быть быстрее (т.к. нет лишней передачи данных между сервером и клиентом + выполняется скомпилированный MySQL-код - быстрее интерпретируемого php)

Попробовал так:
Код: sql
1.
2.
SELECT QUERY1 INNER JOIN (QUERY2) AS query2 ON (query1.id = query2.id)
WHERE COND1


Но такой вариант выполняется медленнее, чем первоначальный (т.к. индексов в этом запросе нет, то перебираются каждый с каждым).

Т.е. здесь нужно получать НЕ декартово произведение, а выполнить элементарную арифметическую операцию со списками (пересечение списков).
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39010849
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если сделать так:
Код: sql
1.
SELECT query1.id WHERE query1.id IN (QUERY2)

то MySQL начинает выполнять QUERY2 для каждой записи из QUERY1

MySQL настолько туп, что не может определить, что запрос QUERY2 никак не связан с внешним запросом QUERY1 ?
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39010853
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Т.е. мне вообще непонятно, как в MySQL:
а) ОДНОКРАТНО выполнить подзапрос (который никак не связан с основным запросом)
б) проверить вхождение идентификатора записи из основного запроса в множество идентификаторов, возвращённых вложенным подзапросом
в) при этом скорость выполнения такого запроса должна быть приблизительно такой же (разве что чуть-чуть больше), что и отдельное последовательное выполнение этих запросов
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39010914
tanglir
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02MySQL настолько туп, что не может определить, что запрос QUERY2 никак не связан с внешним запросом QUERY1 ?да
в 5.6 вроде поправили, но насколько качественно, хз

Cyrax_02как
Код: sql
1.
2.
3.
4.
5.
select *
from абырвалг
join (
 подзапрос, который никак не связан с основным запросом
) t0 on абырвалг.id=t0.id

если не устраивает, давайте конкретный текст вашего "каменного цветка"
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39010921
Merdoc
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02Т.е. мне вообще непонятно, как в MySQL:
в) при этом скорость выполнения такого запроса должна быть приблизительно такой же (разве что чуть-чуть больше), что и отдельное последовательное выполнение этих запросов
Мне кажется это вообще не реально . Сама выборка гораздо менее затратная штука, чем последующая связка.
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39011156
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tanglir
Код: sql
1.
2.
3.
4.
5.
select *
from абырвалг
join (
 подзапрос, который никак не связан с основным запросом
) t0 on абырвалг.id=t0.id


Этот вариант я уже прокомментировал:
авторПопробовал так:
Код: sql
1.
2.
SELECT QUERY1 INNER JOIN (QUERY2) AS query2 ON (query1.id = query2.id)
WHERE COND1

Но такой вариант выполняется медленнее, чем первоначальный (т.к. индексов в этом запросе нет, то перебираются каждый с каждым).
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39011159
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторМне кажется это вообще не реально. Сама выборка гораздо менее затратная штука, чем последующая связка.
Как мы сами убедились, на уровне декартовых множеств связка выполняется слишком медленно (очевидно, это связано с тем, что работа идёт со строками, а не с числами + обусловлено декартовой логикой).

Посему нужно вычислять не декартово произведение, а арифметическое. Арифметическое произведение числовых списков.
Либо заставить MySQL выполнять независимый вложенный запрос в WHERE только 1 раз
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39011232
tanglir
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02Этот вариант я уже прокомментировал:
авторПопробовал так:
Код: sql
1.
2.
SELECT QUERY1 INNER JOIN (QUERY2) AS query2 ON (query1.id = query2.id)
WHERE COND1


Но такой вариант выполняется медленнее, чем первоначальный (т.к. индексов в этом запросе нет, то перебираются каждый с каждым).Прокомментировали, только вот ни реального запроса, ни хотя бы планов не показали.
И почему "WHERE COND1" - снаружи?
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39011336
biwed.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Cyrax_02, Добрый день.

Если query1.id уникальный, то вашу задачу можно решить через UNION ALL + group by. Почти аналогичная задача приводилась 16945040 , а решение приводил тут 16949405

PS. Было бы здорово, если при постановке задачи приводить таблички с данными, а то писать SQL скрипты как-то не охото.

С уважением,
biwed.ru
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39011373
bochkov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02Если сделать так:
Код: sql
1.
SELECT query1.id WHERE query1.id IN (QUERY2)

то MySQL начинает выполнять QUERY2 для каждой записи из QUERY1

MySQL настолько туп, что не может определить, что запрос QUERY2 никак не связан с внешним запросом QUERY1 ?
не должен он так делать,
что то тут не так
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39011381
miksoft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
bochkovCyrax_02Если сделать так:
Код: sql
1.
SELECT query1.id WHERE query1.id IN (QUERY2)

то MySQL начинает выполнять QUERY2 для каждой записи из QUERY1

MySQL настолько туп, что не может определить, что запрос QUERY2 никак не связан с внешним запросом QUERY1 ?не должен он так делать,
что то тут не такТем не менее, такой баг есть. Исправлен он только начиная с версии 5.6.
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39011744
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторне должен он так делать,
что то тут не так Именно так и происходит. Проверил в режиме профилирования

авторЕсли query1.id уникальный, то вашу задачу можно решить через UNION ALL + group byТочно. А ведь сам не догадался... Только в Вашем варианте ещё having нужно будет использовать.
Завтра протестирую этот вариант и сравню со своим (свой вариант я тоже придумал и тоже на UNION). Отпишусь.
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39012110
alex564657498765453
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
miksoftbochkovпропущено...
не должен он так делать,
что то тут не такТем не менее, такой баг есть. Исправлен он только начиная с версии 5.6.

да, а меня всегда это удивляло...ведь есчё до работы с базой, просто читая книжку по мусклу без привязки к субд - уже знал, что есть кореллированные подзапросы и независимые, и потом очень удивился что мускл их не различает
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39012170
miksoft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alex564657498765453miksoftТем не менее, такой баг есть. Исправлен он только начиная с версии 5.6.да, а меня всегда это удивляло...ведь есчё до работы с базой, просто читая книжку по мусклу без привязки к субд - уже знал, что есть кореллированные подзапросы и независимые, и потом очень удивился что мускл их не различаетВообще - различает. Баг касается только конструкции IN (SELECT ... ).
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39012182
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторВообще - различает. Баг касается только конструкции IN (SELECT ... )Если только этой конструкции, тогда её нужно переконструировать так, чтобы логика осталась прежней, но конструкция - иной (в которой глюк не наблюдается).
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39012185
miksoft
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Cyrax_02авторВообще - различает. Баг касается только конструкции IN (SELECT ... )Если только этой конструкции, тогда её нужно переконструировать так, чтобы логика осталась прежней, но конструкция - иной (в которой глюк не наблюдается).Собственно, так всегда и делаем - советуем переписать через JOIN или через EXISTS.
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39012814
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Результат таков:

1) Классический вариант с INNER JOIN и с использованием наиболее подходящих индексов: 0.08 сек
2) Вариант с IN (SELECT) в версии MySQL до 5.6: 15 сек (подзапрос выполняется много раз - баг MySQL)
3) Вариант с EXISTS (коррелированный подзапрос): 15 сек

4) Мой вариант (получение 2 наборов идентификаторов - на уровне SQL, вычисление пересечения - на уровне php):

Код: sql
1.
2.
3.
4.
SELECT (
    (SELECT GROUP_CONCAT(DISTINCT ... SEPARATOR '_') AS ids FROM ... WHERE ...) AS ids1,
    (SELECT GROUP_CONCAT(DISTINCT ... SEPARATOR '_') AS ids FROM ... WHERE ...) AS ids2
)

Код: php
1.
2.
$idsPacked = ВЫПОЛНЯЕМ ЗАПРОС
$fastIds = array_intersect(explode('_', $idsPacked[0]['ids1']), explode('_', $idsPacked[0]['ids2']));

Здесь запрос выполняется = 0.0238-0.241 сек, [explode + intersect] = 0.0050-0.0052 сек. Итого: 0.0289-0.0294 сек

5) Вариант, предложенный biwed.ru :
Код: sql
1.
2.
3.
4.
5.
6.
SELECT IDS.id FROM (
    SELECT DISTINCT ... AS id, 1 AS intersect
UNION ALL
    SELECT DISTINCT ... AS id, 1 AS intersect
) AS IDS
GROUP BY IDS.id HAVING (SUM(intersect) = 2)

Здесь обязательно:
а) должны присутствовать DISTINCT (чтобы в пределах одной группы идентификаторов нельзя было набрать [intersect = 2])
б) должен быть UNION ALL (чтобы сохранить все идентификаторы, присутствующие в обоих выборках)

Такой запрос выполняется 0.0277-0.283 сек , что на 0.001 сек быстрее предыдущего варианта (вывод достоверен - тестировал много раз).

Причём если во второй выборке не указывать имена полей [AS id] и [AS intersect] (во второй выборке они не обязательны), то запрос будет выполняться на 0.0005 сек медленнее и соответственно, выигрыш по сравнению с предыдущим вариантом составит 0.0005 сек .

------------------------------------------------------------------------------------------------------
6) Вариант с IN (SELECT) в версии MySQL 5.6 и выше: ??? сек
Скорее всего, этот вариант сработает быстрее всех предложенных.
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39012819
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторТакой запрос выполняется 0.0277-0.283 сек
Опечатка. Должно быть так: 0.0277-0. 0 283 сек
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39012912
biwed.ru
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Cyrax_02, Добрый день.
Cyrax_02 Результат таков:

5) Вариант, предложенный biwed.ru :
Код: sql
1.
2.
3.
4.
5.
6.
SELECT IDS.id FROM (
    SELECT DISTINCT ... AS id, 1 AS intersect
UNION ALL
    SELECT DISTINCT ... AS id, 1 AS intersect
) AS IDS
GROUP BY IDS.id HAVING (SUM(intersect) = 2)

Здесь обязательно:
а) должны присутствовать DISTINCT (чтобы в пределах одной группы идентификаторов нельзя было набрать [intersect = 2])
б) должен быть UNION ALL (чтобы сохранить все идентификаторы, присутствующие в обоих выборках)

DISTINCT можно убрать переписав запрос. Получится как-то так.
Код: sql
1.
2.
3.
4.
5.
6.
SELECT IDS.id FROM (
    SELECT  ... AS id, 1 AS intersect_1, NULL AS intersect_2
UNION ALL
    SELECT  ... AS id, NULL, 1
) AS IDS
GROUP BY IDS.id HAVING (MIN(intersect_1) = MIN(intersect_2))



С уважением,
biwed.ru
...
Рейтинг: 0 / 0
Пересечение наборов (списков) на уровне SQL-запроса
    #39013361
Cyrax_02
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
biwed.ruDISTINCT можно убрать, переписав запрос. Получится как-то так:
Код: sql
1.
2.
3.
4.
5.
6.
SELECT IDS.id FROM (
    SELECT  ... AS id, 1 AS intersect_1, NULL AS intersect_2
UNION ALL
    SELECT  ... AS id, NULL, 1
) AS IDS
GROUP BY IDS.id HAVING (MIN(intersect_1) = MIN(intersect_2))

Данная модификация (без DISTINCT) ускоряет запрос ещё на 0.0015 сек .
...
Рейтинг: 0 / 0
20 сообщений из 20, страница 1 из 1
Форумы / MySQL [игнор отключен] [закрыт для гостей] / Пересечение наборов (списков) на уровне SQL-запроса
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]