如果我有以下表结构...
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或空白,我可以排除标记表上的连接的最“高效”方式是什么?
答案 0 :(得分:2)
指定条件连接的唯一方法(也是最好的方法)是使用不同的查询:
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是一种声明性的数据访问语言,而不是您的应用程序命令式处理语言。您声明的任何查询都必须创建一个在所有情况下 的访问路径。在查询中使用条件逻辑是您可以做的最糟糕的事情,它会强制通常扫描所有可能数据的访问计划,因为他们无法确定计划创建时条件是真还是假时间。
答案 1 :(得分:0)
我不认为指定左连接会导致性能下降(如果@tagstring为null或空白,我假设@searchTags为空)。
或者你不想因在标签上加入@searchTags而导致性能下降吗?
在你的例子中,@ searchtags中的数据来自于
,这一点并不十分清楚LEFT JOIN Tags t on t.TagId = bt.TagId AND @tagstring is not null AND @tagstring <> ''
服务器应该足够智能,以便在存在该条件时根本不尝试加入。在任何情况下,我都不认为这会导致任何显着的性能下降。
如果你因为某种原因想要在结果中没有显示列,那么带有两个不同查询的IF ... ELSE块是最简单的方法。
答案 2 :(得分:0)
我认为如果@tagstring为null或空白,您可以获得的最佳性能是不运行查询。由于所有内部联接和@searchTags都没有行,因此永远不会返回行。
因此,当真正阻塞时,您可以将SELECT语句移动到IF语句中。