【问题标题】:Creating a table using explicit create table statement versus select into使用显式 create table 语句与 select into 创建表
【发布时间】:2011-07-26 15:04:20
【问题描述】:

使用显式创建表语句和加载数据与选择进入之间是否存在性能差异。此示例仅显示 2 列,但该问题适用于使用非常大的表。下面的示例也使用临时表,但我也想知道使用常规表的效果。我认为无论表类型如何,它们都是相同的。

临时表场景:

--- Explicitly creating temp table first and then loading.
create table #test1 (id int, name varchar(100))
insert into #test1 (id, name) select id, name from #bigTable

--- Creating temp table by selecting into.
select id,name into #test2 from #bigTable

或常规表格:

--- Explicitly creating table first and then loading.
create table test1 (id int, name varchar(100))
insert into test1 (id, name) select id, name from #bigTable

--- Creating table by selecting into.
select id,name into test2 from bigTable

大家对此有何看法?我认为显式创建表和加载必须具有比 select into 更好的性能,因为 select into 必须评估语句中的表达式才能创建表。

我们的组织通常明确地创建临时表作为标准做法,我们想知道什么才是真正的最佳做法。

http://msdn.microsoft.com/en-us/library/ms188029.aspx

【问题讨论】:

  • 我没有时间检查,但您可能会发现这是重新编译的原因。这种潜在的开销是否大于 Adam Houldsworth 所暗示的其他好处,我会留给你或其他人去了解:)
  • 你检查过这两个变种的执行计划了吗?你真的给他们计时,看看是否有可测量的差异吗?
  • 我之前都试过了,但不是在大量数据上。目前我并不想解决任何性能问题,我很好奇每种插入方法的优缺点...

标签: sql sql-server database sql-server-2008


【解决方案1】:

CREATE TABLE 可让您在插入数据之前更好地控制表的定义,例如 NOT NULL、约束等您无法使用 SELECT INTO 执行的操作。

SELECT INTO 是最低限度记录的操作,但INSERT..SELECT 在某些情况下也可以最低限度地记录。
请参阅The Data Loading Performance Guide,尤其是以下部分:Summarizing Minimal Logging conditions

简而言之,如果您不关心约束等(例如,您想快速创建表的副本)SELECT..INTO 恕我直言的优势是更短的代码。
否则,您应该使用其他方式,您仍然可以将其记录到最低限度。

【讨论】:

  • 感谢您的链接,看起来是一篇很棒的文章。以后一定要读一读。
【解决方案2】:

Select into 有日志记录的好处(没有那么多),所以在大多数情况下性能实际上更好。但是,如果表存在,它会出错,并且不会构建诸如索引或约束之类的东西,只是列。

看你需要什么。我知道我们有一些SELECT ... INTO 然后重命名的操作,因为它比更新旧表更快(显然有很多绒毛来重建表对象等)。

请记住,我们的使用不与临时表一起使用,我刚刚在您的问题中注意到就是这种情况。

对于带有索引的表,insert into 必须在插入过程中维护索引。然后还有其他可能导致更多处理的表对象,例如触发器。在选择进入的情况下,据我所知,该表是准系统,因此初始插入性能非常好。加上事务日志的影响是最小的(在你问题的那个链接中提到这一点)。

这实际上取决于使用情况,对于临时表,我假设它们的寿命相对较短,因此选择进入后跟截断/删除可以很好地工作。如果它们具有更长的跨度,但在其他方面被丢弃,则再次选择进入,然后最终丢弃可以工作。

如果它们在创建后需要很长时间并且不会被丢弃,那么除了最初创建和插入数据(这将很快)之外,您将在后续插入方面回来并保持一致 - 您最好只调整表以接受快速插入,例如通过使用最少的索引或禁用之前的索引并重新启用后插入。

在碰巧有聚集索引的大表的情况下,我还看到了一个技巧,其中插入的数据在插入时按聚集索引排序。

【讨论】:

  • 我会修改问题,无论表类型如何,我都想知道性能
  • 你知道SELECT ... INTO #temp 是否会导致重新编译吗?
【解决方案3】:

在我的例子中,执行显式 CREATE 然后 INSERT INTO 在实际运行时间和优化器估计的成本方面都表现得明显更好。

我的临时表不大(8 行),但其中一个值是计算得到的字符串值。在某些情况下,此临时表与具有数十万行的结果集相连接。我相信当我为我的临时表执行 SELECT INTO 时,它并没有为计算值选择最佳数据类型。因此,当我使用 CREATE 显式定义列数据类型时,SQL Server 能够更有效地执行连接。当然,这种效果被夸大了,因为涉及的行太多了。

因此,在某些情况下,特别是当您的列之一是计算值时,CREATE 和 INSERT 可能是更好的选择。当然,您的里程可能会有所不同,因此请务必进行一些测试!

【讨论】:

    猜你喜欢
    • 2011-12-04
    • 1970-01-01
    • 2011-08-17
    • 2020-02-08
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    相关资源
    最近更新 更多