Понимание, как СОЕДИНЕНИЕ работает, когда 3 или больше таблицы включены. [SQL]

Интересно, может ли кто-либо помочь улучшиться, мое понимание Участвует в SQL. [Если это значительно к проблеме, я думаю SQL Server MS конкретно.]

Возьмите 3 таблицы A, B [Связанное, чтобы быть некоторым A.AId], и C [B связаны с C некоторым B.BId]

Если я составляю запрос, например,

SELECT *
FROM A JOIN B 
ON A.AId = B.AId

Вся польза - я мил с тем, как это работает.

Что происходит, когда Таблица C (Или некоторый другой D, E.... добавляется),

В ситуации

SELECT *
FROM A JOIN B 
  ON A.AId = B.AId
JOIN C ON C.BId = B.BId

К чему присоединяется C? - это что таблица B (и значения в таблице B?) Или это некоторый другой временный набор результатов, который является результатом Соединения A+B, к которому присоединяются к таблице C?

[Импликацией быть не все значения, которые находятся в таблице B, обязательно будет во временном наборе результатов A+B на основе условия объединения для A, B]

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

Tables 
Account (AccountId, AccountBalanceDate, OpeningBalanceId, ClosingBalanceId)
Balance (BalanceId)
BalanceToken (BalanceId, TokenAmount)

Where:
Account->Opening, and Closing Balances are NULLABLE 
(may have opening balance, closing balance, or none)

Balance->BalanceToken is 1:m - a balance could consist of many tokens

Концептуально, Конечное сальдо даты, было бы tomorrows начальное сальдо

Если я пытался найти список всех начальных и конечных сальдо для учетной записи

Я мог бы сделать что-то как

SELECT AccountId
, AccountBalanceDate
, Sum (openingBalanceAmounts.TokenAmount) AS OpeningBalance
, Sum (closingBalanceAmounts.TokenAmount) AS ClosingBalance
FROM Account A 
   LEFT JOIN BALANCE OpeningBal 
      ON A.OpeningBalanceId = OpeningBal.BalanceId
   LEFT JOIN BALANCE ClosingBal 
      ON A.ClosingBalanceId = ClosingBal.BalanceId
   LEFT JOIN BalanceToken openingBalanceAmounts 
      ON openingBalanceAmounts.BalanceId = OpeningBal.BalanceId
   LEFT JOIN BalanceToken closingBalanceAmounts 
      ON closingBalanceAmounts.BalanceId = ClosingBal.BalanceId
   GROUP BY AccountId, AccountBalanceDate  

Вещи работают, как я ожидал бы, пока последнее СОЕДИНЕНИЕ не вводит маркеры конечного сальдо - где я заканчиваю с дубликатами в результате.

[Я могу зафиксировать с ОТЛИЧНЫМ - но я пытаюсь понять, почему то, что происходит, происходит]

Мне сказали, что проблема состоит в том, потому что отношения между Балансом и BalanceToken 1:M - и что, когда я ввожу последнее СОЕДИНЕНИЕ, я получаю дубликаты, потому что 3-е СОЕДИНЕНИЕ уже ввело BalanceIds многократно в (я принимаю), временный набор результатов.

Я знаю, что таблицы в качестве примера не соответствуют хорошему дизайну DB

Извинения за эссе, спасибо за любой elightenment :)

Редактирование в ответ на вопрос Marc

Концептуально для учетной записи не должно быть дубликатов в BalanceToken для Учетной записи (на AccountingDate) - я думаю, что проблема появляется, потому что 1 Учетная запись / конечное сальдо AccountingDates - то, что начальное сальдо Учетных записей в течение следующего дня - поэтому, когда сам соединяющий с Балансом, BalanceToken многократно для получения начальные и конечные сальдо я думаю Балансы (BalanceId's), приносится в 'соединение результата' многократно. Если это помогает разъяснить второй пример, думать о нем как о ежедневном согласовании - следовательно оставленный соединения - начальное (и/или) конечное сальдо не могло быть вычислено для сделанного отчета / accountingdate комбинация.

68
задан Ugo 14 November 2019 в 13:53
поделиться

4 ответа

Концептуально вот что происходит, когда вы объединяете три таблицы вместе.

  1. Оптимизатор предлагает план, который включает порядок объединения. Это может быть A, B, C или C, B, A или любая из комбинаций
  2. Механизм выполнения запросов применяет любые предикаты (предложение WHERE ) к первой таблице, которая не включает никаких других таблиц. Он выбирает столбцы, упомянутые в условиях JOIN , списке SELECT или списке ORDER BY . Назовите этот результат A
  3. . Он присоединяет этот набор результатов ко второй таблице. Для каждой строки он присоединяется ко второй таблице, применяя любые предикаты, которые могут применяться ко второй таблице. Это приводит к другому временному набору результатов.
  4. Затем он присоединяется к итоговой таблице и применяет ORDER BY

Это происходит концептуально. Фактически, на этом пути есть много возможных оптимизаций. Преимущество реляционной модели состоит в том, что надежная математическая основа делает возможными различные преобразования плана, не изменяя при этом его правильность.

Например, действительно нет необходимости генерировать полные наборы результатов в процессе. Вместо этого ORDER BY может выполняться путем доступа к данным, в первую очередь, с использованием индекса. Также можно выполнить множество типов соединений.

на самом деле нет необходимости генерировать полные наборы результатов по пути. Вместо этого ORDER BY может выполняться путем доступа к данным, в первую очередь, с использованием индекса. Также можно выполнить множество типов соединений.

на самом деле нет необходимости генерировать полные наборы результатов по пути. Вместо этого ORDER BY может выполняться путем доступа к данным, в первую очередь, с использованием индекса. Также можно выполнить множество типов соединений.

42
ответ дан 24 November 2019 в 14:23
поделиться

Мы знаем, что данные из B будут отфильтрованы (внутренним) соединением с A (данные в A также фильтруются). Итак, если мы (внутреннее) присоединяемся от B к C , то набор C будет также , отфильтрованным отношением к A . Также обратите внимание, что любые дубликаты из соединения будут включены .

Однако; в каком порядке это происходит, зависит от оптимизатора; он может решить сначала выполнить соединение B / C , затем ввести A или любую другую последовательность (возможно, на основе предполагаемого количества строк из каждого соединения и соответствующие индексы).


ОДНАКО; в вашем более позднем примере вы используете соединение LEFT OUTER ; поэтому Аккаунт не фильтруется вообще , и вполне может быть дублирован, если какая-либо из других таблиц имеет несколько совпадений.

Есть ли дубликаты (для каждой учетной записи) в BalanceToken ?

5
ответ дан 24 November 2019 в 14:23
поделиться

Я часто считаю, что помогает просмотреть фактический план выполнения. В Query Analyzer / Management Studio вы можете включить это для запросов из меню Query или использовать Ctrl + M. После выполнения запроса план, который был выполнен, отображается на другой вкладке результатов. Из этого вы увидите, что сначала соединяются C и B, а затем результат соединяется с A. План может варьироваться в зависимости от информации, имеющейся в СУБД, потому что оба соединения являются внутренними, что делает его A-and-B-and-C . Я имею в виду, что результат будет одним и тем же независимо от того, какое соединение будет выполнено первым, но время, необходимое для этого, может сильно отличаться, и именно здесь в игру вступают оптимизатор и подсказки.

1
ответ дан 24 November 2019 в 14:23
поделиться

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

Не видя таблиц, трудно дать четкий ответ в ваш конкретный случай, но я думаю, что основная проблема заключается в том, что вы суммируете несколько наборов результатов, которые объединяются в один.

Возможно, вместо нескольких объединений вы должны создать в своем запросе две отдельные временные таблицы, одну с идентификатором учетной записи, датой и суммой начальных балансов, вторую с идентификатором учетной записи, датой и суммой конечных балансов, а затем объединить эти две таблицы по идентификатору учетной записи. и дату.

Чтобы точно узнать, что происходит с объединениями, в том числе и в вашем конкретном случае, я бы сделал следующее:

Изменил начальную часть

SELECT accountID Accountbalancedate, sum (...) как начальный баланс, sum (...) как закрывающий баланс FROM

до простого

«SELECT * FROM»

Изучите полученную таблицу, и вы увидите, какие именно данные дублируются. Удалите объединения одно за другим и посмотрите, что произойдет. Это должно дать вам представление о том, что именно в ваших данных вызывает дублирование.

Если вы открываете запрос в SQL Server Management Studio (существует бесплатная версия), вы можете редактировать запрос в дизайнере. Визуальное представление того, как соединяются таблицы, также может помочь вам понять, что происходит.

1
ответ дан 24 November 2019 в 14:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: