Создать оптимальный запрос, чтобы найти записи, которые находятся только в одной таблице - PullRequest
1 голос
/ 16 июня 2009

так скажем, я создаю эту систему управления контактами. Есть таблица USER и таблица CONTACT_INFO. Для каждого ПОЛЬЗОВАТЕЛЯ у меня может быть ноль или более записей CONTACT_INFO. Как я определил, я настроил внешний ключ в своей таблице CONTACT_INFO, чтобы он указывал на соответствующую запись USER.

Я бы хотел выполнить поиск по всем записям ПОЛЬЗОВАТЕЛЯ, в которых нет записей CONTACT_INFO.

Я ожидаю, что это можно сделать:

SELECT * FROM user u WHERE u.user_id NOT IN (SELECT DISTINCT c.user_id FROM CONTACT_INFO);

Меня беспокоит то, что по мере роста таблиц производительность этого запроса может значительно снизиться.

Одна из идей, с которыми я играю, - добавить в таблицу USER столбец, в котором будет указано, есть ли в нем записи CONTACT_INFO или нет. Кроме того, мне было интересно, если после вставки какой-либо записи в CONTACT_INFO СУБД должна проверить, существует ли эта запись, она уже будет обращаться к этой записи для проверки и, следовательно, обновлять ее, когда я обновляю запись CONTACT_INFO, не следует. это дорого, с точки зрения производительности.

Как всегда, обратная связь приветствуется.

Ответы [ 4 ]

3 голосов
/ 16 июня 2009

Самый простой способ это:

SELECT (...) 
FROM user u
LEFT OUTER JOIN CONTACT_INFO c
ON u.user_id = c.user_id
WHERE c.user_id IS NULL

Это выглядит более громоздко, но должно масштабироваться лучше.

2 голосов
/ 16 июня 2009

Из моих тестов следующее быстрее, чем метод BradC:

select (...)
from user u
where not exists (select null from CONTACT_INFO c where u.user_id = c.user_id)

Это может быть из-за того, что компилятор должен сам выполнить преобразование, я не знаю.

Ле Дорфье в принципе верен: если вы настроили свои индексы прямо в базе данных (то есть должны индексироваться оба столбца user_id), и ваш ответ, и большинство этих ответов здесь будут очень быстрыми, независимо от того, как много записей в вашей базе данных.

Кстати, если вы ищете способ получить запрос, который перечисляет пользователей вместе с логическим значением HasContactInfo, вы можете сделать что-то вроде этого:

select u.(...), 
  (case when exists (select null from CONTACT_INFO c where c.user_id = u.user_id) then 1
        else null
        end) has_contact_info
from user u

Это второе решение может оказаться бесполезным в вашем случае, но я обнаружил, что оно намного быстрее, чем некоторые более простые запросы, которые, как я предполагал, будут оптимизированы автоматически.

1 голос
/ 16 июня 2009

По крайней мере, в Oracle, я получаю лучшую производительность, используя

, где 0 = (выберите количество (*) из CONTACT_INFO c, где ...)

вместо предложения NOT IN.

1 голос
/ 16 июня 2009

Есть ли у вас основания полагать, что производительность будет ухудшаться? Это один из самых эффективных типов запросов в SQL. Но отбросьте ОТЛИЧИЕ.

...