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 с двумя различными запросами - это самый простой способ сделать это.

Другие вопросы по тегам