加入SELECT与Join to Tableset

时间:2014-02-06 15:52:05

标签: sql sql-server performance tsql database-performance

对于那里的DB专家,我想知道在结合SELECT语句和加入先前填充的表变量之间是否存在任何功能/性能差异。我在SQL Server 2008 R2中工作。

示例(TSQL):

-- Create a test table
DROP TABLE [dbo].[TestTable]
CREATE TABLE [dbo].[TestTable](
    [id] [int] NOT NULL,
    [value] [varchar](max) NULL
) ON [PRIMARY]
-- Populate the test table with a few rows
INSERT INTO [dbo].[TestTable]
SELECT 1123, 'test1'

INSERT INTO [dbo].[TestTable]
SELECT 2234, 'test2'

INSERT INTO [dbo].[TestTable]
SELECT 3345, 'test3'

-- Create a reference table
DROP TABLE [dbo].[TestRefTable]
CREATE TABLE [dbo].[TestRefTable](
    [id] [int] NOT NULL,
    [refvalue] [varchar](max) NULL
) ON [PRIMARY]
-- Populate the reference table with a few rows
INSERT INTO [dbo].[TestRefTable]
SELECT 1123, 'ref1'

INSERT INTO [dbo].[TestRefTable]
SELECT 2234, 'ref2'

-- Scenario 1: Insert matching results into it's own table variable, then Join

-- Create a table variable 
DECLARE @subset TABLE ([id] INT NOT NULL, [refvalue] VARCHAR(MAX))

INSERT INTO @subset
SELECT * FROM [dbo].[TestRefTable] 
WHERE [dbo].[TestRefTable].[id] = 1123

SELECT  t.*, s.*
FROM [dbo].[TestTable] t
JOIN @subset s
ON t.id = s.id 

-- Scenario 2: Join directly to SELECT results
SELECT t.*, s.*
FROM [dbo].TestTable t
JOIN (SELECT * FROM [dbo].[TestRefTable] WHERE id = 1123) s
ON t.id = s.id 

在“真实”世界中,表和表变量是预定义的。我正在看的是能够将匹配的引用行用于进一步的操作,但是我担心额外的步骤会减慢查询速度。是否存在技术原因,为什么一个会比另一个更快?两种方法之间可以看到什么样的性能差异?我意识到很难(如果不是不可能)给出一个明确的答案,只是为这个场景寻找一些建议。

5 个答案:

答案 0 :(得分:2)

这会得到相同的结果吗?

SELECT t.*, s.*
FROM dbo.TestTable AS t
JOIN dbo.TestRefTable AS s ON t.id = s.id AND s.id = 1123

基本上,这是TestTableTestRefTableid = 1123的所有记录的交叉联接。

答案 1 :(得分:2)

数据库引擎有一个优化器来确定执行查询的最佳方法。引擎盖下的内容比你想象的要多。例如,当SQL Server进行连接时,它可以选择至少四种连接算法:

  • 嵌套循环
  • 索引查找
  • 合并加入
  • 哈希加入

(更不用说这些的多线程版本。)

了解每种方法的工作原理并不重要。您只需了解两件事:不同的算法在不同情况下最佳,SQL Server尽力选择最佳算法。

连接算法的选择只是优化器所做的一件事。它还必须弄清楚连接的顺序,聚合结果的最佳方式,order by是否需要排序,如何访问数据(通过索引或直接)等等。

当你打破查询时,你正在做出关于优化的假设。在您的情况下,您假设第一个最好的事情是在特定表上进行选择。你可能是对的。如果是这样,具有多个查询的结果应该与使用单个查询一样快。好吧,也许不是。在单个查询中,SQL Server不必一次缓冲所有结果;它可以将结果从一个地方传输到另一个地方。它也可以以分裂查询的方式利用并行性。

通常,SQL Server优化器非常好,因此您最好让优化器一次性完成查询。肯定存在异常,优化器可能不会选择最佳执行路径。有时修复此问题就像确保统计信息是最新的表格一样简单。其他时候,您可以添加优化程序提示。有时您可以重新构建查询,就像您所做的那样。

例如,将数据加载到本地表有用的一个地方是表来自不同的服务器。优化器可能没有关于表大小的完整信息以做出最佳决策。

换句话说,将查询保留为一个语句。如果您需要改进它,那么在它工作之后专注于优化。您通常不必花费太多时间进行优化,因为引擎非常擅长。

答案 2 :(得分:2)

加入表变量也会导致优化器的基数估计值不佳。优化器始终假定表变量仅包含单个行。它实际上拥有的行越多,估计变得越差。这会导致优化器为表本身假定行数错误,但在其他地方,对于可能然后加入该结果的运算符,可能导致错误估计该操作的执行次数。

我个人认为Table参数应该用于使用客户端应用程序(C#.Net应用程序充分利用它们)方便地将数据输入和输出服务器,或者用于在存储过程之间传递数据,但也不应该使用在proc本身内部。在Proc代码中删除它们的重要性随着参数携带的预期行数而增加。

Sub Selects将更好地执行,或立即复制到临时表将很好地工作。复制到临时表有开销,但同样,你拥有的行越多,开销就越有价值,因为优化器的估计越来越差。

答案 3 :(得分:1)

通常,查询中的派生表可能比加入表变量更快,因为它可以使用索引,但它们在表变量中不可用。但是,临时表也可以创建索引,这可能会解决潜在的性能差异。

此外,如果表变量记录的数量预计很小,那么索引无论如何都不会产生很大的差异,因此几乎没有差别。

作为alawys,您需要在自己的系统上测试记录的数量,而表设计和索引设计与最有效的方法有很大关系。

答案 4 :(得分:0)

期望直接表连接比表变量更快,并且使用更少的资源。