SQL - наиболее эффективный способ условно исключить объединение? (если это вообще возможно)
Если у меня есть следующая структура таблицы...
Table 1: BlogPost
PostId | Name | Text
Table 2: Tags
TagId | Tag
Table 3: BlogPostTag
PostId | TagId
И следующая хранимая процедура...
CREATE PROCEDURE SearchBlogPosts
@tagstring nvarchar(max),
AS
BEGIN
DECLARE @searchTags TABLE (Tag varchar(50));
IF @tagstring IS NOT NULL AND @tagstring <> ''
BEGIN
INSERT INTO @tags SELECT s AS tag FROM dbo.Split(',',@tagstring);
END
SELECT * FROM BlogPost b
JOIN BlogPostTags bt on bt.PostId = b.PostId
JOIN Tags t on t.TagId = bt.TagId
JOIN @searchTags st ON st.Tag = t.Tag
...
(Other Joins and where clauses may exist below here)
END
... какой самый "производительный" способ, которым я мог бы исключить объединения в таблицах тегов, если @tagstring имеет значение null или пусто?
3 ответа
Единственный способ (а также лучший способ) указать условные объединения - это иметь разные запросы:
IF @tagstring IS NOT NULL AND @tagstring <> ''
BEGIN
SELECT * FROM BlogPost b
JOIN BlogPostTags bt on bt.PostId = b.PostId
JOIN Tags t on t.TagId = bt.TagId
JOIN @searchTags st ON st.Tag = t.Tag
END
ELSE
BEGIN
SELECT * FROM BlogPost b
JOIN BlogPostTags bt on bt.PostId = b.PostId
JOIN Tags t on t.TagId = bt.TagId
END
SQL является декларативным языком доступа к данным, а не языком императивной обработки вашего приложения. Любой запрос, который вы объявляете, должен создавать путь доступа, который работает во всех случаях. Наличие условной логики в запросе - худшая вещь, которую вы можете сделать, это вызывает планы доступа, которые обычно сканируют все возможные данные, потому что они не могут определить, являются ли условия истинными или ложными во время создания плана.
Я думаю, что лучшая производительность, которую вы можете получить, это не запускать запрос, если @tagstring имеет значение null или пусто. Поскольку все внутренние объединения и @searchTags не имеют строк, вы никогда не получите возвращаемые строки.
So, you can move the SELECT statement into the IF statement, when true block.
Я не думаю, что указание левого соединения повлечет за собой снижение производительности (я предполагаю, что @searchTags пусто, если @tagstring равно нулю или пусто).
Или вы не хотите понизить производительность за присоединение тегов @searchTags к тегам?
В вашем примере не совсем понятно, откуда берутся данные в @searchtags.
LEFT JOIN Tags t on t.TagId = bt.TagId AND @tagstring is not null AND @tagstring <> ''
Сервер должен быть достаточно умным, чтобы вообще не пытаться присоединиться к нему с этим условием. Я бы не подумал, что это может привести к значительному снижению производительности в любом случае.
Если вы хотите, чтобы столбцы вообще не отображались в результате, по какой-то причине блок IF...ELSE с двумя различными запросами - это самый простой способ сделать это.