У меня есть три таблицы, A, B, C, где A много к одному B, а B много к одному C. Мне нужен список всех C в A.
Мои таблицы выглядят примерно так: A [id, valueA, lookupB], B [id, valueB, lookupC], C [id, valueC]. Я написал запрос с двумя вложенными SELECT, но мне интересно, можно ли каким-то образом выполнить INNER JOIN с DISTINCT.
SELECT valueC
FROM C
INNER JOIN
(
SELECT DISTINCT lookupC
FROM B INNER JOIN
(
SELECT DISTINCT lookupB
FROM A
)
A2 ON B.id = A2.lookupB
)
B2 ON C.id = B2.lookupC
Обновлено: Таблицы довольно большие, A - 500 тыс. Строк, B - 10 тыс. Строк, а C - 100 строк, поэтому, если я сделаю базовое внутреннее соединение и использую DISTINCT в конце, будет много ненужной информации, например:
SELECT DISTINCT valueC
FROM
C INNER JOIN B on C.id = B.lookupB
INNER JOIN A on B.id = A.lookupB
Это очень и очень медленно (по величине в разы медленнее, чем вложенный SELECT, который я сделал выше.


Это то, что вы имеете в виду?
SELECT DISTINCT C.valueC
FROM
C
INNER JOIN B ON C.id = B.lookupC
INNER JOIN A ON B.id = A.lookupB
Я изменил порядок соединения, который, в зависимости от того, какой SQL вы используете, может улучшить производительность запроса.
Я считаю, что ваши отношения 1: м уже должны неявно создавать DISTINCT JOIN.
Но если ваша цель состоит только в C в каждом A, может быть проще просто использовать DISTINCT в самом внешнем запросе.
SELECT DISTINCT a.valueA, c.valueC
FROM C
INNER JOIN B ON B.lookupC = C.id
INNER JOIN A ON A.lookupB = B.id
ORDER BY a.valueA, c.valueC
Этого оказалось достаточно, проблема заключалась в том, что у меня не было индекса.
SELECT DISTINCT C.valueC
FROM C
LEFT JOIN B ON C.id = B.lookupC
LEFT JOIN A ON B.id = A.lookupB
WHERE C.id IS NOT NULL
Я не вижу веской причины, по которой вы хотите ограничить наборы результатов A и B, потому что вы хотите иметь список всех C, на которые ссылается A. Я выделил C.valueC, потому что я догадался, что вы хотел уникальный список троек.
РЕДАКТИРОВАТЬ: Я согласен с вашим аргументом. Даже если ваше решение выглядит немного вложенным, оно кажется лучшим и самым быстрым способом использовать ваши знания данных и сократить наборы результатов.
Нет отдельной конструкции соединения, которую вы могли бы использовать, поэтому просто оставайтесь с тем, что у вас уже есть :)
Результат тот же, но вроде медленнее. Я не знаю точно, почему, но я предполагаю, что это потому, что он создает две огромные таблицы соединения с C.valueC будет очень большим. Поскольку я знаю, что B.lookupC должен быть ОТЛИЧИТЕЛЬНЫМ сам по себе, я хочу использовать эти знания, чтобы ускорить процесс.
Я провел тест на MS SQL 2005, используя следующие таблицы: A 400K строк, B 26K строк и C 450 строк.
Предполагаемый план запроса показал, что базовое внутреннее соединение будет в 3 раза медленнее, чем вложенные подзапросы, однако при фактическом выполнении запроса базовое внутреннее соединение было в два раза быстрее, чем вложенные запросы. Базовое внутреннее соединение заняло 297 мс на очень высоком уровне. минимальное серверное оборудование.
Какую базу данных вы используете и какое время видите? Я думаю, что если вы видите низкую производительность, это, вероятно, проблема с индексом.
Это была проблема с индексированием. Я использую MSSQL 2005 и наконец нашел помощника по настройке ядра СУБД. Я добавил индекс на A.lookupB, и это значительно ускорило работу. Спасибо за вашу помощь!
К сожалению, это кажется очень медленным, поскольку сначала нужно создать огромные таблицы соединений. Когда я запускаю свой код, он работает быстрее, я полагаю, это связано с тем, что он сокращает таблицы соединений.