Чем заменить левое соединение в представлении, чтобы иметь индексированное представление? - PullRequest
17 голосов
/ 25 июня 2011

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

Вопрос о соединении, где одна колонка на одной стороне равна нулю

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

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

  1. Почему индексация не допускается для внешних или собственных соединений?
  2. Есть ли какие-либо потери производительности в этом неиндексированном представлении?
  3. Кто-нибудь знает какой-нибудь способ обойти эту проблему?

Я только что закончил курс SQL Server вчера, поэтому не знаю, как продолжить. Буду признателен за любые комментарии. Приветствия.

Ответы [ 5 ]

13 голосов
/ 01 июля 2015

Вот альтернатива.Вам нужно материализованное представление A, не содержащее B. Это не доступно напрямую ... поэтому вместо этого материализуйте два представления.Один из всех А и один только А с B.Затем получите только A, не имеющие B, взяв A, кроме B. Это можно сделать эффективно:

Создать два материализованных представления (mA и mAB) ( edit: mA может быть просто базовой таблицей ).У mA отсутствует соединение между A и B (таким образом, содержит все точки A [и, следовательно, содержит эти записи БЕЗ совпадений в B]).Соединение mAB между A и B (таким образом, содержит только A с B [и, следовательно, исключая эти записи БЕЗ совпадений в B]).

Чтобы получить все A без совпадений в B, замаскируйте те, которые соответствуют:

with ids as (
  select matchId from mA with (index (pk_matchid), noexpand)
  except
  select matchId from mAB with (index (pk_matchid), noexpand)
)
select * from mA a join ids b on a.matchId = b.matchId;

Это должно привести к левому анти-полусоединению с вашими кластерными индексами, чтобы получить идентификаторы, и с кластеризованным индексом, чтобы получить данные из mA, которые вы ищете.

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

7 голосов
/ 25 июня 2011

Существует "обходной путь" здесь , который включает проверку на NULL в соединении и имеет NULL значение представления в таблице

NULL значение

INSERT INTO Father (Father_id, Father_name) values(-255,'No father')

Объединение

JOIN [dbo].[son] s on isnull(s.father_id, -255) = f.father_id
6 голосов
/ 26 ноября 2012

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

Select * 
into <REAL_TABLE>
From <VIEW>

create CLUSTERED index <INDEX_THE_FIELD> on <REAL_TABLE>(<THE_FIELD>)

Но это только заслуживающий внимания подход, если данные не обновляются каждые несколько секунд.

1 голос
/ 05 февраля 2013

Логически вы делаете два отдельных запроса.«A LEFT JOIN B» - это просто сокращение для «(A JOIN B) UNION A»

Первый запрос - это таблица A, внутренняя, соединенная с таблицей B. Получается индексированное представление, поскольку здесь все тяжелыеПодъем завершен.

Второй запрос - это просто таблица A, в которой любой из столбцов соединения имеет значение null.Создайте представление, которое выдает те же выходные столбцы, что и первый запрос, и дополняет их нулями.

Просто объедините два результата, прежде чем возвращать их.Нет необходимости в обходном пути.

0 голосов
/ 25 июня 2011

Я поработаю над ответом на 1, а пока:

[2].Представление будет не более и не менее производительным, чем эквивалентный запрос к изменяющимся таблицам.Все обычные советы применимы к наличию индексов покрытия, предпочтительно индексов для соединенных столбцов и т. Д.

[3].Там нет реального обхода.Большинство ограничений для индексированных представлений существуют по очень веским причинам, как только вы в них разберетесь.

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

Я постараюсь добавить ответ на 1, как только восстановлю его в своем собственном уме.

...