2009-01-15 87 views
5

这是一个未解决的问题,但我真的很想听听人们的意见。SQL Server中的临时表用法

我很少使用显式声明的临时表(表变量或常规#tmp表),因为我相信不这样做会导致更简洁,可读和可调试的T-SQL。我也认为SQL可以做得比我在需要时使用临时存储(比如在查询中使用派生表)时做得更好。

唯一的例外是数据库不是典型的关系数据库,而是星形或雪花模式。我知道最好先将过滤器应用于事实表,然后使用生成的临时表来获取维度中的值。

这是常见的观点还是有人有反对意见?

回答

14

临时表对于像报表或ETL作业这样的复杂批处理过程非常有用。一般而言,您希望在事务性应用程序中很少使用它们。

如果您使用包含多个大表的联接(可能是为报表)进行复杂查询,查询优化程序可能实际上无法在一次匹配中对其进行优化,因此临时表成为这里的胜利 - 它们会分解查询到一系列较简单的查询优化器,以减少搞砸计划的机会。有时你有一个操作无法在单个SQL语句中完成,因此需要多个处理步骤来完成这项工作。再次,我们在这里谈论更复杂的操作。

您也可以为中间结果创建临时表,然后为表建立索引,甚至可能在其上放置聚集索引以优化后续查询。这也可能是一种快速且肮脏的方式,可以在不允许向数据库架构添加索引的系统上优化报表查询。 SELECT INTO对于这种类型的操作很有用,因为它被最小化记录(因此速度很快),并且不需要对齐选择和插入的列。

其他原因可能包括使用CROSS APPLY和xpath查询从XML字段中提取数据。通常将其提取到临时表中然后在临时表上工作会更有效。对于某些任务,它们比CTE的速度快得多,因为它们实现了查询结果,而不是重新评估查询。

需要注意的一件事是,临时表的结构与查询引擎用来存储中间连接结果的结构完全相同,因此使用它们不会有性能损失。临时表还允许使用设置操作的多阶段任务,并使T-SQL代码中的游标几乎(不是完全但几乎)不必要。

'Code Smell'是一个多报,但如果我看到很多涉及临时表的简单操作,我会想知道发生了什么。

3

我将临时表看作是一种SQL代码异味,只能用作最后的手段。如果您在获得最终结果集之前必须缓存数据,那么它通常表示对我来说数据库设计不合适。

+0

这是我的意见,但我只是想知道我是否是一个势利眼! – 2009-01-15 15:17:26

+1

需要注意的一件事是,糟糕的数据库设计比您想象的要普遍得多。如果您想体验处理坏数据库设计后果的乐趣,请尝试在数据仓库中工作几年。 – ConcernedOfTunbridgeWells 2009-01-15 20:04:48

5

这真的取决于你在做什么。我通常会尽量避免它们,但有时您需要做一些复杂的事情,需要采取多个步骤。一般来说,这远远超出了表格中简单的选择。像其他任何东西一样,它是一个你必须知道何时使用的工具。

我同意你的看法,我通常会让db在幕后处理这些东西,但有些时候它的优化已关闭,你必须手动进行。

+0

你是对的。当它很复杂且直接的SQL不执行并且临时表执行时,你将要做什么? – 2009-01-15 15:36:50

0

我也是,避免临时表。我的理解是,MS SQL Server上的临时表总是在主数据库的文件组中。这意味着,虽然您的生产应用程序表很可能位于一些昂贵的高性能RAID设置中,但您的临时表位于MS SQL Server的安装位置,这些位置很可能位于Program Files目录下的C:驱动器中。

3

临时表当然有适当的用途,如果正确使用它们不是代码味道。关于它们的好处之一是它们位于tempdb中,通常设置为简单恢复模式。这意味着如果您使用临时表来表达他们的优点(主要是批量操作),那么与生产数据库中的表相同的操作相比,您可以生成最少量的日志,这可能是在完全恢复模式。

如果如另一张海报所示,您的生产数据库在良好的硬件上,但您的tempdb不在,请让您的DBA移动它。 SQL Server本身使用tempdb来处理您的查询,因此tempdb具有高性能的主目录很重要。

表变量是完全不同的生物。他们只活在记忆中。对他们来说一个很好的用法是,如果你有一个函数,你需要用CROSS APPLY来查询查询中的每一行。如果该函数的开销很大,但是可以从中获得的不同结果的数量很少,那么可以通过预先计算所有可能调用的结果(或者可能是所有可能的数据集调用的结果)并将其存储在表变量,然后加入到该表变量,而不是使用CROSS APPLY。

0

当您有一个数据集需要检索一次并在随后的语句中反复使用时也很有用。

使这些较长的批处理过程更具可读性(有时这比性能更重要)。