在 T-Sql 插入语句中使用 Row Constructor 语法有啥好处?

Posted

技术标签:

【中文标题】在 T-Sql 插入语句中使用 Row Constructor 语法有啥好处?【英文标题】:What are the benefits of using the Row Constructor syntax in a T-Sql insert statement?在 T-Sql 插入语句中使用 Row Constructor 语法有什么好处? 【发布时间】:2012-03-29 18:42:14 【问题描述】:

在 SQL Server 2008 中,您可以使用 Row Constructor 语法通过单个插入语句插入多行,例如:

insert into MyTable (Col1, Col2) values
  ('c1v', 0),
  ('c2v', 1),
  ('c3v', 2);

除了可读性之外,这样做而不是为每条记录使用一个插入语句还有其他好处吗?

【问题讨论】:

【参考方案1】:

是的,两者之间存在相当大的性能差异:

declare @numbers table (n int not null primary key clustered);

insert into @numbers (n)
values (0)
     , (1)
     , (2)
     , (3)
     , (4);

declare @numbers table (n int not null primary key clustered);

insert into @numbers (n) values (0);
insert into @numbers (n) values (1);
insert into @numbers (n) values (2);
insert into @numbers (n) values (3);
insert into @numbers (n) values (4);

每个insert 语句都有自己的隐式事务这一事实保证了这一点。您可以通过查看每个语句的执行计划或使用set statistics time on; 对执行进行计时来轻松地向自己证明这一点。对于每个单独的插入,“设置”和“拆除”上下文有一个固定的成本,第二个查询必须支付五次此罚金,而第一个查询只支付一次。

list 方法不仅效率更高,而且您还可以使用它来构建派生表:

select *
from (values
    (0)
  , (1)
  , (2)
  , (3)
  , (4)
) as Numbers (n);

这种格式绕过了 1,000 个值的限制,允许您在插入列表之前加入和过滤列表。人们可能还会注意到我们根本不受insert 语句的约束!作为一个事实上的表,这个结构可以在任何表引用有效的地方使用。

【讨论】:

如果通过网络连接发送大量单独的 INSERT 语句,也会显着提高性能。 @GordThompson 绝对是。如果您在网络上使用单独的语句插入 10,000 行,那么您至少会浪费 240,000 个字节,仅通过线路发送字符串 insert into 10,000 次。在此之后为表/列名称添加的每个字符都是另外两个字节,必须在我上面的帖子中写的任何内容开始应用之前发送、接收和解析......【参考方案2】:

是的 - 您将看到性能改进。尤其是对于大量记录。

【讨论】:

实际上,如果通过网络连接发送大量单独的 INSERT 语句,则会显着提高性能。有关示例,请参见 my answer here。 编辑了一个错误的答案以使其在多年后改正? :) 很遗憾,这个线程上这个问题的唯一正确答案来自 Kittoes1024 并且没有标记为答案(这让我认为 OP 的答案标记应该由版主更正)。【参考方案3】:

如果除了显式键入的行之外,您还要插入多列带有SELECT 的数据,则表值构造器将要求您单独拼写每一列,而不是使用一个@987654323 @语句,可以在SELECT中指定多列。

例如:

USE AdventureWorks2008R2;
GO
CREATE TABLE dbo.MyProducts (Name varchar(50), ListPrice money);
GO
-- This statement fails because the third values list contains multiple columns in the subquery.
INSERT INTO dbo.MyProducts (Name, ListPrice)
VALUES ('Helmet', 25.50),
       ('Wheel', 30.00),
       (SELECT Name, ListPrice FROM Production.Product WHERE ProductID = 720);
GO

会失败;你必须这样做:

INSERT INTO dbo.MyProducts (Name, ListPrice)
VALUES ('Helmet', 25.50),
       ('Wheel', 30.00),
       ((SELECT Name FROM Production.Product WHERE ProductID = 720),
        (SELECT ListPrice FROM Production.Product WHERE ProductID = 720));
GO

见Table Value Constructor Limitations and Restrictions

【讨论】:

【参考方案4】:

正如 Abe 所说,没有性能优势。

列构造函数的顺序是值(或选择语句)所需的顺序。您可以按任何顺序列出列 - 值必须遵循该顺序。

如果你不小心在 select 语句(或 values 子句)中切换了列并且数据类型是兼容的,使用 columns 构造将帮助你找到问题。

【讨论】:

以上是关于在 T-Sql 插入语句中使用 Row Constructor 语法有啥好处?的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL 语句中的前缀 N 是啥意思,啥时候应该使用它?

使用T-SQL语句操作数据表-插入数据

T-SQL语句中使用select…………union 插入数据是为啥不能使用DEFAULT

使用 T-SQL Merge 语句时如何避免插入重复记录

使用T-SQL语句插入更新删除数据表

使用T-SQL语句操纵数据库表