Чем заменить левое соединение в представлении, чтобы я мог иметь индексированное представление?

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

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

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

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

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


person Noble_Bright_Life    schedule 25.06.2011    source источник
comment
Вам нужны столбцы из ВНЕШНЕЙ таблицы?   -  person gbn    schedule 25.06.2011
comment
Если вам действительно нужно индексированное представление, вы можете создать (индексированное) INNER JOIN. Затем вы можете СЛЕВА СОЕДИНЯТЬ исходную (левую) таблицу с этим представлением, чтобы получить желаемый результат, но с приростом производительности индексированного представления.   -  person ypercubeᵀᴹ    schedule 25.06.2011
comment
@gbn & @ypercube: да, мне нужен столбец в левой внешней таблице, и, к сожалению, именно здесь мне нужно включить уникальный кластерный индекс.   -  person Noble_Bright_Life    schedule 25.06.2011


Ответы (5)


здесь есть "обходной путь", который включает проверку 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
person Magnus    schedule 25.06.2011
comment
@Damien, @gbn: Это только мне кажется, что это обходное решение ужасно? Что происходит с другими запросами с SELECT COUNT(*) FROM rightTable? Вам придется изменить их, чтобы исправить ошибку (на 1), которую они выдадут после обходного пути? - person ypercubeᵀᴹ; 26.06.2011
comment
@ypercube, ваше право, это ужасно и на самом деле не является обходным решением. Но это единственный способ добиться желаемого. Лучшим решением может быть индексирование базовых таблиц и пропуск индексированного представления. - person Magnus; 26.06.2011
comment
@Damien, как гласит старая идиома: нищие не могут выбирать - person Martin Capodici; 24.10.2017

Вот альтернатива. Вам нужно материализованное представление A, не содержащее B. Это недоступно напрямую ... поэтому вместо этого материализуйте два представления. Один из всех A и один из только A с 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 намного лучше справляется с данными, которые ЕСТЬ там, чем с данными, которых НЕТ. Материализовав два источника, вы получите несколько привлекательных опций, основанных на множестве. Вы должны сами взвесить стоимость этих представлений и этих достижений.

person cocogorilla    schedule 01.07.2015

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

Select * 
into <REAL_TABLE>
From <VIEW>

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

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

person Klaus    schedule 26.11.2012
comment
Хорошее решение. Нет необходимости каждый раз обновлять всю таблицу. Мы можем писать триггер и обновлять только измененные строки. - person Dmitriy Startsev; 18.03.2015
comment
Как бы мне ни не нравились ручные обновления таблиц ... все может быть легко "потеряно" .. это может быть жизнеспособным в определенных ситуациях. - person user2864740; 29.10.2018
comment
Проблема с пакетными операциями, производительность будет низкой. Также необходимо позаботиться об удалении обновления записи, что требует дополнительного обслуживания. - person suhas0sn07; 16.04.2019

По логике, вы делаете два отдельных запроса. 'A LEFT JOIN B' - это просто сокращение от '(A JOIN B) UNION A'

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

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

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

person Anon    schedule 05.02.2013
comment
Это по-прежнему не будет работать, поскольку индексы не разрешены в представлениях, которые используют ключевые слова UNION, INTERSECT или EXCEPT. - person a11smiles; 27.04.2015
comment
Попробуйте, прежде чем заявить, что это не сработает. UNION представлений могут использовать индексы для базовых представлений. - person Anon; 27.04.2015
comment
Я просто попробовал это сделать, но получить индексированное представление, использующее UNION, НЕВОЗМОЖНО. Проверьте здесь msdn.microsoft.com/en-us/library/ms191432. aspx # Ограничения - person ilija veselica; 14.07.2015
comment
Создайте индексное представление C для A JOIN B, затем используйте обычное представление для C union A. - person Irawan Soetomo; 15.03.2016

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

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

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

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

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

person Damien_The_Unbeliever    schedule 25.06.2011
comment
Ленивость программистов MS конструировать индексированные представления для a LEFT JOIN b LEFT JOIN ... LEFT JOIN z? - person ypercubeᵀᴹ; 25.06.2011
comment
@ypercube - большинство ограничений существует, потому что они позволяют поддерживать индексированное представление без необходимости выполнять полное сканирование таблицы для одной или нескольких базовых таблиц (например, почему разрешены только агрегаты SUM, и только если также включено COUNT_BIG), или выполнить другие дорогостоящие операции. - person Damien_The_Unbeliever; 25.06.2011
comment
Спасибо, что ответили на мои другие вопросы. Ваше здоровье. - person Noble_Bright_Life; 25.06.2011
comment
За исключением того, что LEFT JOIN (по крайней мере, с некоторыми ограничениями условий соединения) не требует дополнительных сканирований индекса, кроме INNER JOIN. Отсутствие поддержки этого базового сценария LEFT JOIN делает индексированные представления мусором для расширения схем: так что в данном случае это дефект функции / функциональности. - person user2864740; 03.01.2021