Вместо того, чтобы независимо объединять несколько таблиц, использовать отдельные запросы? - PullRequest
5 голосов
/ 31 января 2011

Я часто выполняю пару независимых соединений со стола. Например, скажем, у нас есть таблица collections, которая имеет независимые отношения «один к N» как с photos, так и с songs, где N - от нуля до многих.

Теперь, скажем, мы хотим получить коллекцию, и и (независимо) связанные с ней фотографии и песни.

Обычно я бы использовал что-то вроде этого:

SELECT
    collections.collectionid as collectionid,
    photos.name as photo_name,
    songs.name  as song_name

FROM collections
    LEFT JOIN photos ON collections.collectionid = photos.collectionid
    LEFT JOIN songs  ON collections.collectionid = songs.collectionid

WHERE collections.collectionid = 14

Конечно, соединение левой таблицы с двумя другими таблицами, если первое соединение приводит к M строкам, а второе к N строкам, дает M * N строк. Это может показаться неоптимальным с точки зрения трафика и производительности базы данных.

+--------------+------------+-----------+
| collectionid | photo_name | song_name |
+--------------+------------+-----------+
| 14           | 'x'        | 'a'       | \
| 14           | 'x'        | 'b'       |  - Each photo is returned 3 times,
| 14           | 'x'        | 'c'       | /  because 3 songs are returned.
| 14           | 'y'        | 'a'       | \
| 14           | 'y'        | 'b'       | 
| 14           | 'y'        | 'c'       | /
+--------------+------------+-----------+

Кроме того, вы можете выполнить два выбора: два отдельных запроса, каждый из которых объединяет collections в другую таблицу, давая M + N строк:

SELECT
    collections.collectionid as collectionid
    song.name as song_name
FROM collections
    LEFT JOIN songs on collections.collectionid = songs.collectionid
WHERE collections.collectionid = 14

и

SELECT
    collections.collectionid as collectionid
    photos.name as photo_name
FROM collections
    LEFT JOIN photos on collections.collectionid = photos.collectionid
WHERE collections.collectionid = 14

дает:

+--------------+------------+    +--------------+------------+
| collectionid | song_name  |    | collectionid | photo_name |
+--------------+------------+    +--------------+------------+
| 14           | 'a'        |    | 14           | 'x'        |
| 14           | 'b'        |    | 14           | 'y'        |
| 14           | 'c'        |    +--------------+------------+
+--------------+------------+

Мой вопрос: как лучше всего с этим справиться?

Ничего из вышеперечисленного не кажется оптимальным. Итак, есть ли другой способ, который приводит к M + N строкам, но может быть выполнен в одном запросе?

Ответы [ 2 ]

5 голосов
/ 26 октября 2011

Ваш первый вариант (два независимых СОЕДИНЕНИЯ), по-видимому, не дает вам очень полезного набора результатов (поскольку две вспомогательные таблицы производят полукартовой продукт, и вам необходимо дублировать результаты в коде приложения) .

Второй вариант (два отдельных запроса) приемлем, если только вы не хотите обрабатывать результаты двух запросов как один набор для целей презентации (например, сортировать их все вместе по полю даты).

Лучшее решение, я думаю, состоит в том, чтобы объединить два запроса в один с UNION ALL, создав один набор результатов только с теми строками, которые вам действительно нужны:

SELECT
  collections.collectionid as collectionid,
  photos.name as photo_name,
  'photo' as document_type
FROM collections
  LEFT JOIN photos on collections.collectionid = photos.collectionid
WHERE collections.collectionid = 14
UNION ALL
SELECT
  collections.collectionid as collectionid,
  song.name as photo_name
  'song' as document_type
FROM collections
  LEFT JOIN songs on collections.collectionid = songs.collectionid
WHERE collections.collectionid = 14

Этот тип результирующего набора может быть ORDERed BY любым полем во всем комбинированном наборе записей, что позволяет (например) получить 20 самых последних документов, прикрепленных к коллекции, независимо от их типа.

0 голосов
/ 31 января 2011

Кажется, что связь между фотографиями и разрешениями не определена, что приводит к перекрестному соединению, о котором вы говорите. Да, на первый взгляд, выполнение двух запросов лучше, чем у вас. Однако реальный вопрос заключается в том, почему фотографии и разрешения не связаны между собой на основе ключей.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...