2013-05-27 63 views
27

这是一个关于SQL Server 2008 R2的问题为什么临时表和子查询之间有巨大的性能差异

我不是DBA,到目前为止。我是一名Java开发人员,他不得不随时写SQL。 (主要嵌入代码中)。我想知道我在这里做错了什么,如果是的话,我可以做些什么来避免它再次发生。

Q1:

SELECT something FROM (SELECT * FROM T1 WHERE condition1) JOIN ... 

Q1特征14联接

Q2相同Q1,有一个例外。 (SELECT * FROM T1 WHERE condition1)之前执行,并存储在临时表中。

这不是一个相关的子查询。

Q2:

SELECT * INTO #tempTable FROM T1 WHERE condition1 
SELECT something FROM #tempTable JOIN ... 

再次,14连结。

现在让我感到困惑的是Q1花费了2分钟(试了几次,以避免缓存发挥作用),而Q2(两个查询相结合)花了2秒!是什么赋予了?

+3

我的猜测是'SELECT * FROM T1 WHERE condition1'的估计行数非常不准确。将它物化为'#tempTable'意味着SQL Server确切地知道将返回多少行。你能发布两种实际执行计划的XML版本吗? –

回答

40

它为什么不推荐使用子查询?

数据库优化器(无论您使用的是哪个数据库)不能总是正确地优化此类查询(使用子查询)。在这种情况下,优化器的问题是选择正确的方式来加入结果集。有几种连接两个结果集的算法。算法的选择取决于包含在一个和另一个结果集中的记录数。如果您加入两个物理表(子查询不是物理表),则数据库可以通过可用的统计信息轻松确定两个结果集中的数据量。如果其中一个结果集是子查询,那么要了解它返回的记录数是非常困难的。在这种情况下,数据库可能会选择错误的连接查询计划,这会导致查询性能的显着降低。

使用临时表重写查询旨在简化数据库优化器。在重写的查询中,所有参与连接的结果集都将是物理表,并且数据库将轻松确定每个结果集的长度。这将允许数据库选择所有可能的查询计划中保证的最快速度。而且,无论条件如何,数据库都会做出正确的选择。用临时表重写的查询在任何数据库上都能正常工作,这在便携式解决方案的开发中尤为重要。此外,重写的查询更易于阅读,更易于理解和调试。

据了解,使用临时表重写查询可能会导致一些额外开支的减速:创建临时表。如果数据库不会被错误地选择查询计划,那么它将比旧的查询更快地执行旧的查询。但是,这种放缓总是微不足道的。通常创建临时表需要几毫秒。也就是说,延迟不会对系统性能产生重大影响,通常可以忽略。

重要!不要忘记为临时表创建索引。索引字段应包含连接条件中使用的所有字段。

+1

SQL Server查询引擎在内部创建临时表,并且您在上面提供的原因并非总是如此.IT取决于很多其他因素,如索引,分段,统计等。 – AnandPhadke

+2

在临时表上创建索引可提高查询性能。 – nirupam

+1

你的回答是相当具有误导性和错误的,创建一个临时表应该只在某些情况下考虑:http://stackoverflow.com/questions/42772428/should-all-sub-queries-be-replaced-with-temporary-tables ?noredirect = 1#comment72660694_42772428 – Arvand

相关问题