一次性事务和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-2中的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的使用有较明显的提高。此外,插入大数据到表中,有无索引和日志恢复模式也会影响插入的性能。
-------补充-----
这里补充一下CTE1中记录数的生成。如果只需要100万的数据量,只需要master.sys.databases表CROSS JOIN自己一次就可以了,或者找两张表CROSS JOIN后数据更接近的所需就更好了,不够的可以UNIONL ALL几次。那如果需要1000万或更大的记录数,可以在此基础上再CROSS JOIN一次一张小表,比如:
;WITH CTE3 AS (
SELECT a.[object_id] FROM master.sys.all_objects AS a, master.sys.all_objects AS b, master.sys.databases AS c
) SELECT COUNT(*) AS counts,LEN(COUNT(*)) AS counts_length FROM CTE3
GO
code-5

figure-1
我的机器上生成了1亿1多千万条记录。
一次性事务和CTE插入数据的比较的更多相关文章
- (C#版本)提升SQlite数据库效率——开启事务,极速插入数据,3秒100万,32秒1000万条数据
SQLite插入数据效率最快的方式就是:开启事务 + insert语句 + 关闭事务(提交) 利用事务的互斥性,如果在批量的插入操作前显式地开启一次事务,在插入操作结束后,提交事务,那么所有 ...
- 普通的jdbc事务在插入数据后 下面的代码报错时 数据不会回滚 但是 spring的事务会回滚
普通的jdbc事务在插入数据后 下面的代码报错时 数据不会回滚 但是 spring的事务会回滚
- 使用事务和SqlBulkCopy批量插入数据
SqlBulkCopy是.NET Framework 2.0新增的类,位于命名空间System.Data.SqlClient下,主要提供把其他数据源的数据有效批量的加载到SQL Server表中的功能 ...
- C#使用SqlTransaction事务回滚与SqlBulkCopy批量插入数据
C#中批量处理数据,有时候因为一条记录导致整个批量处理失败.这时候肯能会导致数据不全等问题,这时候我们可以使用SqlTransaction来进行事务回滚,即是要么全部成功要么全部不成功.如下代码 // ...
- 【Update】C# 批量插入数据 SqlBulkCopy
SqlBulkCopy的原理就是通过在客户端把数据都缓存在table中,然后利用SqlBulkCopy一次性把table中的数据插入到数据库中. SqlConnection sqlConn = new ...
- C#批量插入数据到Sqlserver中的四种方式
我的新书ASP.NET MVC企业级实战预计明年2月份出版,感谢大家关注! 本篇,我将来讲解一下在Sqlserver中批量插入数据. 先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的 ...
- C#_批量插入数据到Sqlserver中的四种方式
先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记 ...
- C# 之 批量插入数据到 SQLServer 中
创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快.而如果存在索引的情况下,每次插入记录都会进行索引重建,这是非常耗性能的.如 ...
- C#批量插入数据到Sqlserver中的四种方式 - 转
先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记 ...
随机推荐
- 使用 Redis 实现分布式锁
这里有一篇文章介绍了用redis实现分布式的方式 .不是简简单单的用setnx来实现,讲述了几种实际项目中的一些情况.猛击下面链接查看 http://www.oschina.net/translate ...
- Si2155
http://www.edom.com.tw/cn/index.jsp?m=prodview&id=1702 Description:新型的Si2155 电视调谐器IC扩展了Silicon L ...
- 配置TortoiseSVN客户端, 强制签入前加注释
正如上篇提到, 总有一些人在签入代码到SVN前没有加注释, 然后, 像这样: 鬼才知道改了什么东西. ①有些人可能就是没有写注释的习惯, ②有些人可能是忘记写注释 && SVN服务端和 ...
- 【原】iphone6来了,我该做点什么(兼容iphone6的方法)
北京时间2014年9月10日凌晨1点,苹果公司正式发布其新一代产品 iPhone6,相信做webapp开发的同学对它是充满了好奇和等待,也担心它带来各种坑爹,高清的分辨率,升级的retina显示屏,我 ...
- size_t和size_type
size_t和size_type是为了独立于及其而定义的类型,因为比如在一台电脑上int为2b,而另一台电脑上是4b,这样就给程序的可移植性带来了麻烦.为了解决这个问题,在库内定义了如上类型,其实si ...
- sicily vector有序插入
实现了简单的vector有序插入,这个题目值得注意的点是1.当vector为空时,需要判断再排除 2.迭代器的使用是此段代码的特点 int insertVector(vector<int> ...
- 第7章 权限管理(3)_文件系统属性和sudo权限
3. 文件系统属性chattr权限 (1)chattr命令 命令格式: #chattr [+-=][选项] 文件或目录名 +.-.= 分别表示增加权限.删除权限和赋于某种权限 选项 i:主要用来防止对 ...
- LUA类
cpp_object_map = {}setmetatable(cpp_object_map, { __mode = "kv" }) local search_basesearch ...
- MySQL数据库备份--mysqldump用法
导出要用到MySQL的mysqldump工具,基本用法是: shell> mysqldump [OPTIONS] database [tables] 如果你不给定任何表,整个数据库将被导出. ...
- JS组件系列——使用HTML标签的data属性初始化JS组件
前言:最近使用bootstrap组件的时候发现一个易用性问题,很多简单的组件初始化都需要在JS里面写很多的初始化代码,比如一个简单的select标签,因为仅仅只是需要从后台获取数据填充到option里 ...