一次性事务和CTE插入数据的比较

有时要构造一些数据来做测试数据,像下面这样:

IF OBJECT_ID(N‘T14‘) IS NOT NULL
BEGIN
    DROP TABLE T14
END
GO
CREATE TABLE T14 (t14_id INT)
GO

DECLARE @i INT = 1
WHILE @i <= 1000
BEGIN
    INSERT INTO T14 (t14_id)
    SELECT @i
    SET @i = @i + 1
END
GO

code-1

这里存在一个问题,每运行一次insert相当于commit了一次事务,数据量小的还不会出现问题,如果把要插入100万,200万,1000万甚至更多的数据呢?既然insert语句是隐式commit的,在这个循环外面加一个显式的事务,即可显著提高插入的性能。另一种方法就是使用CTE也可以一次把数据插入到表中,从而提高性能。现在就这两种方法插入数据的性能来做一个比较。没有结果之前,猜猜哪种速度更快?或者两者差不多?

首先是加事务,插入100万条记录:

IF OBJECT_ID(N‘T14‘) IS NOT NULL
BEGIN
    DROP TABLE T14
END
GO
CREATE TABLE T14 (t14_id INT)
GO

DBCC FREESESSIONCACHE
DBCC DROPCLEANBUFFERS
GO

SET NOCOUNT ON;
BEGIN TRAN
DECLARE @i INT = 1
WHILE @i <= 1000000
BEGIN
    INSERT INTO T14 (t14_id)
    SELECT @i
    SET @i = @i + 1
END
COMMIT TRAN;
SET NOCOUNT OFF;
GO

code-2

我的机器上测试多次,取平均值,大概使用了22秒即可完成100万条记录的插入,速度还是挺快的。(如果没有加显式事务,要多久才能完成呢?有兴趣的朋友可以试下

下面是使用CTE:

IF OBJECT_ID(N‘T15‘) IS NOT NULL
BEGIN
    DROP TABLE T15
END
GO
CREATE TABLE T15 (t15_id INT)
GO

DBCC FREESESSIONCACHE
DBCC DROPCLEANBUFFERS
GO

WITH CTE1 AS (
SELECT a.[object_id] FROM master.sys.all_objects AS a, master.sys.all_objects AS b
)
,CTE2 AS (
SELECT ROW_NUMBER() OVER (ORDER BY [object_id]) as row_no FROM CTE1
)

INSERT INTO T15 (t15_id)
SELECT row_no  FROM CTE2 WHERE row_no <= 1000000
GO

code-3

也是测试多次取平均值,竟然是5秒左右就完成,大大出乎我的意料!现在改为插入1000万条记录,看结果如何。前者只需把code-3中的1000000修改为10000000,再运行即可。后者由于CTE1的记录数不够,需要UNION ALL两次,代码如下:

IF OBJECT_ID(N‘T15‘) IS NOT NULL
BEGIN
    DROP TABLE T15
END
GO
CREATE TABLE T15 (t15_id INT)
GO

DBCC FREESESSIONCACHE
DBCC DROPCLEANBUFFERS
GO

WITH CTE1 AS (
SELECT a.[object_id] FROM master.sys.all_objects AS a, master.sys.all_objects AS b
UNION ALL
SELECT a.[object_id] FROM master.sys.all_objects AS a, master.sys.all_objects AS b
UNION ALL
SELECT a.[object_id] FROM master.sys.all_objects AS a, master.sys.all_objects AS b
)
,CTE2 AS (
SELECT ROW_NUMBER() OVER (ORDER BY [object_id]) as row_no FROM CTE1
)

INSERT INTO T15 (t15_id)
SELECT row_no  FROM CTE2 WHERE row_no <= 10000000
GO

code-4

测试结果:加事务的插入大概需要3分多钟,而CTE则不超过1分半钟的时间就完成了。看来还是CTE更高效啊!在测试过程中,发现内存的使用量不多,但CPU的使用有较明显的提高。此外,插入大数据到表中,有无索引和日志恢复模式也会影响插入的性能。

时间: 2024-11-05 14:57:32

一次性事务和CTE插入数据的比较的相关文章

使用事务和SqlBulkCopy批量插入数据

SqlBulkCopy是.NET Framework 2.0新增的类,位于命名空间System.Data.SqlClient下,主要提供把其他数据源的数据有效批量的加载到SQL Server表中的功能.类似与 Microsoft SQL Server 包中名为 bcp 的命令行应用程序.但是使用 SqlBulkCopy 类可以编写托管代码解决方案,性能上优于bcp命令行应用程序,更优于如Insert方式向SQL Server表加载大量数据.SqlBulkCopy可以应用到大批量数据的转移上,而不

向mysql中批量插入数据的性能分析

MYSQL批量插入数据库实现语句性能分析 假定我们的表结构如下 代码如下   CREATE TABLE example (example_id INT NOT NULL,name VARCHAR( 50 ) NOT NULL,value VARCHAR( 50 ) NOT NULL,other_value VARCHAR( 50 ) NOT NULL) 通常情况下单条插入的sql语句我们会这么写: 代码如下   INSERT INTO example(example_id, name, valu

C#_批量插入数据到Sqlserver中的四种方式

先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记录的ID的值然后再进行加1运算要少.而如果存在索引的情况下,每次插入记录都会进行索引重建,这是非常耗性能的.如果表中无可避免的存在索引,我们可以通过先删除索引,然后批量插入,最后再重建索引的方式来提高效率. create database CarSYS;    go    use CarSYS;  

SQL Server 批量插入数据的两种方法(转)

在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题.下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters). 运行下面的脚本,建立测试数据库和表值参数. [c-sharp] view plaincopy --Create DataBase create database BulkTestDB; go use BulkTes

SQL Server 批量插入数据的两种方法

在SQL Server 中插入一条数据使用Insert语句,但是如果想要批量插入一堆数据的话,循环使用Insert不仅效率低,而且会导致SQL一系统性能问题.下面介绍SQL Server支持的两种批量数据插入方法:Bulk和表值参数(Table-Valued Parameters). 运行下面的脚本,建立测试数据库和表值参数. [c-sharp] view plaincopy --Create DataBase create database BulkTestDB; go use BulkTes

.Net批量插入数据到SQLServer数据库,SqlBulkCopy类批量插入大数据到数据库

批量的的数据导入数据库中,尽量少的访问数据库,高性能的对数据库进行存储. 采用SqlBulkCopy来处理存储数据.SqlBulkCopy存储大批量的数据非常的高效,将内存中的数据表直接的一次性的存储到数据库中,而不需要一次一次的向数据库Insert数据. 经过几次实验,百万级别的数据表,也只需几秒时间内就可以完全的存入数据库中,其速度,比传统的Insert into方法不止快很多倍. 下面看代码: /// <summary> /// 批量插入数据 /// </summary> /

Android批量插入数据到SQLite数据库

Android中在sqlite插入数据的时候默认一条语句就是一个事务,因此如果存在上万条数据插入的话,那就需要执行上万次插入操作,操作速度可想而知.因此在Android中插入数据时,使用批量插入的方式可以大大提高插入速度. 有时需要把一些数据内置到应用中,常用的有以下2种方式:其一直接拷贝制作好的SQLite数据库文件,其二是使用系统提供的数据库,然后把数据批量插入.我更倾向于使用第二种方式:使用系统创建的数据库,然后批量插入数据.批量插入数据也有很多方法,那么那种方法更快呢,下面通过一个dem

java批量插入数据进数据库中

方式1: for循环,每一次进行一次插入数据. 方式2: jdbc的preparedStatement的batch操作 PreparedStatement.addBatch(); ...... PreparedStatement.executeBatch(); 一次最多不要超过50条:1.因为当你插入的时候 数据库已经锁定,然而如果你一次性插入太多会造成其他业务的等待.2.会造成内存的溢出 方式2的本质是:insert into table (a,b,c,d) values(av,bv,cv.d

Bulk Insert 高效快速插入数据

BULK INSERT以用户指定的格式复制一个数据文件至数据库表或视图中. 语法: 1 BULK INSERT [ [ 'database_name'.][ 'owner' ].]{ 'table_name' FROM 'data_file' } 2 WITH ( 3 [ BATCHSIZE [ = batch_size ] ], 4 [ CHECK_CONSTRAINTS ], 5 [ CODEPAGE [ = 'ACP' | 'OEM' | 'RAW' | 'code_page' ] ],