insert into linksvr select VS insert into from linksvr

通过链接服务器将实例A上的数据写入实例B,通常有以下两种方式
--方案1:在实例A上执行
insert into LinkForB.B..TableB select * from TableA
--方案2:在实例B上执行
insert into TableB select * from LinkForA.A..TableA
目前接手的数据库,大量使用链接服务器来搬迁数据,并且使用者随心所欲。本地写入到链接服务器,从链接服务器读数据写入本地,从链接服务器读数据写入到另一链接服务器。更有坑爹的,本来是写入本地,却在本地的前面加上本地实例的链接服务器!
以前没有特别关注哪种方式更好,有在群里针对搬迁数据的方式请教过,有朋友建议最好采用pull的形式链接方式,即insert into TableB select * from LinkForA.A..TableA
直到看到这篇文章,结合自己遇到的问题,尝试分析通过链接服务器insert数据的区别
此处为了方便,我所创建的链接服务器[MY]实际是指向当前实例,但是不影响对结果的分析。
首先创建测试表,并在测试表上创建触发器

USE TEST
GO
--创建测试表
CREATE TABLE [dbo].[Product](
[ProductID] INT,
[Name] [nvarchar](50),
[Remark] [nvarchar](50)
)
GO
--创建触发器
CREATE TRIGGER [dbo].[Product_TR]
ON [dbo]. [Product]
FOR INSERT
AS
BEGIN
SET XACT_ABORT ON
BEGIN TRY
IF (select len(ProductID) from inserted)>0--当select查询只返回一个值时才能操作=、!=、<、<=、>、>=
BEGIN
PRINT ‘one row‘
END
END TRY
BEGIN CATCH
PRINT ‘消息 ‘+CONVERT(VARCHAR,ERROR_NUMBER())+‘,级别 ‘+CONVERT(VARCHAR,ERROR_SEVERITY())
+‘,状态 ‘+CONVERT(VARCHAR,ERROR_STATE())+‘,过程 ‘+CONVERT(VARCHAR,ERROR_PROCEDURE())
+‘,第 ‘+CONVERT(VARCHAR,ERROR_LINE())+‘ 行‘
PRINT ERROR_MESSAGE()
END CATCH
END
GO

注意触发器脚本,是为了在批量插入数据,select...from inserted子查询返回多条记录,进行>操作出错。
插入数据检验

--step1:插入1条数据,成功
INSERT [Test].[dbo].[Product]( [ProductID],[Name],[Remark])
SELECT TOP 1 [ProductID],[Name],‘one row‘
FROM [AdventureWorks2008R2].[Production].[Product]
--step2:插入5条数据,失败
INSERT [Test].[dbo].[Product]( [ProductID],[Name],[Remark])
SELECT TOP 5 [ProductID],[Name],‘more than one row‘
FROM [AdventureWorks2008R2].[Production].[Product]
--step3:插入5条数据到链接服务器,成功
INSERT [MY].[Test].[dbo].[Product]([ProductID],[Name],[Remark])
SELECT TOP 5 [ProductID],[Name],‘ToLink more than one row‘
FROM [AdventureWorks2008R2].[Production].[Product]
--Step4:从链接服务器获取5条数据再插入,失败
INSERT [Test].[dbo].[Product]( [ProductID],[Name],[Remark])
SELECT TOP 5 [ProductID],[Name],‘FromLink more than one row‘
FROM [MY].[AdventureWorks2008R2].[Production].[Product]

我们查看表中结果

通过图中的Remark字段,可以看出step1和step3的语句执行成功,step2和step4的语句执行失败
step1:插入1条数据时,select...from inserted子查询返回1行值,它可和0进行比较(>),数据insert成功。
step2:插入5条数据时,select...from inserted子查询返回5行值,它不能和单一的0进行比较,触发器报错,整个insert语句失败。
step3:插入5条数据到链接服务器,竟然成功!对比前面的语句,说明insert into linksvr.db.sch.tb是一行一行的insert(因为表上有触发器,如果一次多行insert会报错)
step4:当从链接服务器获取5条数据,再insert失败!它近似等效于step2。
现在我们的问题是step3和step4到底哪个更高效?虽然此时我们已经知道,step3会拆分成单条写入,step4一次写入多条。为了让这两个语句正常执行,我们禁用表上的触发器

--禁用/启用触发器
alter table [dbo].[Product]
disable trigger [Product_TR] --disable/enable
--查看触发器
select name,type_desc,create_date,modify_date,is_disabled from sys.triggers t


开启跟踪,然后再次执行step3、step4中的语句

INSERT [MY].[Test].[dbo].[Product]([ProductID],[Name],[Remark])
SELECT TOP 5 [ProductID],[Name],‘ToLink more than one row‘
FROM [AdventureWorks2008R2].[Production].[Product]


在SPID=52窗口执行INSERT Linksvr SELECT TOP 5 FROM语句,链接服务器在SPID=55下执行,有5个RPC:Completed事件

INSERT [Test].[dbo].[Product]( [ProductID],[Name],[Remark])
SELECT TOP 5 [ProductID],[Name],‘FromLink more than one row‘
FROM [MY].[AdventureWorks2008R2].[Production].[Product]


在SPID=52窗口执行INSERT Tab SELECT TOP 5 FROM Linksvr语句,链接服务器在SPID=55的会话中执行,仅一个RPC:Completed事件
此时表中的数据如下

此时全部将表写入到测试表 

Duration字段可以看出insert linksvr要比insert select linksvr耗时些
profile启动跟踪,sys.traces 增加一新记录(status=1),暂停跟踪,原记录的status=0,停止跟踪,原记录删除
profile启动跟踪,sys.traces 增加一新记录(status=1)
SELECT * FROM sys.traces t
语句暂停跟踪
exec sp_trace_setstatus 2, 0
sys.traces 对应记录删除,profile如新创建的跟踪样(暂未开启)
profile启动跟踪,sys.traces 增加一新记录(status=1),暂停跟踪,原记录的status=0
语句启动跟踪
exec sp_trace_setstatus 2, 1
sys.traces 对应记录status=1,说明已启动,但是profile中依旧是暂停状态!
请问此时sys.traces 中的traceid=2的跟踪是否有开启,如果开启了它收集的数据在哪?
此时点击profile中的启动按钮,弹出"在进行修改之前,必须先停止活动跟踪。"
确定,profile恢复成初始状态!

时间: 2024-10-28 17:47:39

insert into linksvr select VS insert into from linksvr的相关文章

INSERT INTO vs SELECT INTO

What is the difference between using SELECT ... INTO MyTable FROM... and INSERT INTO MyTable (...) SELECT ... FROM .... ? From BOL [ INSERT, SELECT...INTO ], I know that using SELECT...INTO will create the insertion table on the default file group if

CREATE TABLE new_tbl_name SELECT * FROM old_tbl_name / INSERT INTO new_tbl_name SELECT * FROM old_tbl_name

DESCRIBE PRODUCTS_TBL; +-----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+--------------+------+-----+---------+-------+ | PROD_ID | varchar(10) | NO | PRI | NULL | | | PROD_DESC |

mybatis之@Select、@Insert、@Delete、@Param

之前学习的时候,看到别人在使用mybatis时,用到@Select.@Insert.@Delete.@Param这几个注解,故楼主研究了一下,在这里与大家分享 当使用这几个注解的时候,可以省去写Mapper.xml等一系列配置文件 首先来看个例子: import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotation

校验Select和Insert的方法

问题简介:在工作中,表字段多到一定程度,Select 中的字段和结果集中的字段对比很麻烦,还容易出错.于是写了一个检查Select和Insert的方法.(使用的是Scala语言) 1.先判断语句是select语句还是insert语句 def sqlTest(str: String): Unit = { //检测是select语句还是insert语句 if ( str.contains("select") ) { selectTest(str) } else { insertTest(s

元素类型为 &quot;mapper&quot; 的内容必须匹配 &quot;(cache-ref|cache|resultMap*|parameterMap*|sql*|insert*|update*|delete*|select)

在配置ssm框架的时候,写mapper映射文件的时候会出现 元素类型为 "mapper" 的内容必须匹配 "(cache-ref|cache|resultMap*|parameterMap*|sql*|insert*|update*|delete*|select) 有时候编译的时候会出现这个bug,是因为在前面写了注释.导致了执行顺序的问题.需要把一些注释删掉,就可以正常执行了. /*mapper动态开发*/ <mapper namespace="com.ss

MyBatis XML 映射器 select、insert update 和 delete、参数

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在. 如果跟JDBC 代码进行对比,省掉了将近 95% 的代码. 1 selectCREATE TABLE person (id int(11) NOT NULL AUTO_INCREMENT,username varchar(100) DEFAULT NULL,password varchar(100) DEFAULT NULL,full_name varchar(100) DEFAULT NULL,first_name varchar

INERT DELEYED、INSERT IGNORE replace into和insert区别

insert into表示插入数据,数据库会检查主键,如果出现重复会报错:replace into表示插入替换数据,需求表中有PrimaryKey,或者unique索引,如果数据库已经存在数据,则用新数据替换,如果没有数据效果则和insert into一样:insert ignore表示,如果表中如果已经存在相同的记录,则忽略当前新数据:测试代码如下: Sql代码   create table testtb( id int not null primary key, name varchar(5

几种常用排序算法(bubble、select、insert、shell、未完待续)

接下来两天重新看看几种常用的排序算法. 1.冒泡排序法 每次从 i=0开始比较相邻的元素,若arr[i]>arr[i+1],则交换它们.直到把最大的元素推向最后.回到 i=0,直至完成. 1 import java.util.Scanner; 2 class bubble 3 { 4 public static void main(String[] args) 5 { 6 int n,temp; 7 int i,j; 8 int[] arr=new int[10000]; 9 Scanner s

mysql之select,insert,delete,update

写在前面 上篇文章学习了创建数据库和数据表,这篇文章将学习对数据表的增删改查操作. 系列文章 mysql之创建数据库,创建数据表 一个例子 上篇文章中,创建了数据库和数据表,数据表中还没有数据,这里我们为三张表中添加数据进行测试. 注意:为了避免字段名或者表明与系统的某些关键字重复,可以使用``包裹字符串,与sql server中的[]类似.``在键盘上方数字键最左边的那个键(英文输入法) 1.添加四个班级信息 use school; -- 添加班级信息 insert into tb_class