动态SQL从表中执行大量行

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态SQL从表中执行大量行相关的知识,希望对你有一定的参考价值。

我有一个包含大量行的表,我希望通过动态SQL执行。它们基本上是存在检查和插入语句,我想将数据从一个生产数据库迁移到另一个生产数据库 - 我们正在合并事务数据。我试图找到执行行的最佳方式。

我一直在找到一种合并方法,用于将所有行相互附加到不高效,尤其是当一次执行的行数大于~100时。

假设源表的结构是任意的,如下所示:

CREATE TABLE [dbo].[MyTable]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[DataField1] [int] NOT NULL,
[FK_ID1] [int] NOT NULL,
[LotsMoreFields] [NVARCHAR] (MAX),
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED ([ID] ASC)
)

CREATE TABLE [dbo].[FK1]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [int] NOT NULL, -- Unique constrained value
CONSTRAINT [PK_FK1] PRIMARY KEY CLUSTERED ([ID] ASC)
)

另一个要求是我正在跟踪源表PK与目标PK以及是否发生了插入或者我是否已将该行迁移到目标。为此,我正在跟踪另一个表中的迁移行,如下所示:

CREATE TABLE [dbo].[ChangeTracking]
(
[ReferenceID] BIGINT IDENTITY(1,1),
[Src_ID] BIGINT,
[Dest_ID] BIGINT,
[TableName] NVARCHAR(255),
CONSTRAINT [PK_ChangeTracking] PRIMARY KEY CLUSTERED ([ReferenceID] ASC)
)

我现有的方法是执行由存储过程生成的一些动态sql。存储的proc执行PK查找,因为源系统具有表[dbo]的不同PK值。[FK1]。例如。

IF NOT EXISTS (<ignore this existence check for now>)
BEGIN
    INSERT INTO [Dest].[dbo].[MyTable] ([DataField1],[FK_ID1],[LotsMoreFields]) VALUES (333,(SELECT [ID] FROM [Dest].[dbo].[FK1] WHERE [Name]=N'ValueFoundInSource'),N'LotsMoreValues');
    INSERT INTO [Dest].[dbo].[ChangeTracking] ([Src_ID],[Dest_ID],[TableName]) VALUES (666,SCOPE_IDENTITY(),N'MyTable'); --666 is the PK in [Src].[dbo].[MyTable] for this inserted row
END

所以当你有一百万这些时,它并不快。

是否有推荐的高效方法?

答案

如上所述,当您查看复杂的JOIN条件时,MERGE语句很有效(如果这些字段中的任何一个不同,则更新记录以匹配)。您还可以考虑创建整个记录的HASHBYTES哈希,以快速找到源表和目标表之间的差异,尽管这对于非常大的数据集来说也很耗时。

另一答案

听起来像是通过检查每一行匹配然后进行插入,就像前端开发人员一样进行这些更新。使用单个查询执行插入会更有效。下面是一个示例,它查找tblNewClient表中的名称,但不在tblClient表中查找:

INSERT INTO tblClient
        ( [Name] ,
          TypeID ,
          ParentID 
          )
SELECT nc.[Name] ,
    nc.TypeID ,
    nc.ParentID
FROM tblNewClient nc
    LEFT JOIN tblClient cl
        ON nc.[Name] = cl.[Name]
WHERE cl.ID IS NULL;

这比RBAR更有效率(通过痛苦排行)。

另一答案

从@RusselFox得到两个答案并将它们放在一起,我达到了这个试验性的解决方案(但看起来效率更高):

MERGE INTO [Dest].[dbo].[MyTable] [MT_D]
USING (SELECT [MT_S].[ID] as [SrcID],[MT_S].[DataField1],[FK_1_D].[ID] as [FK_ID1],[MT_S].[LotsMoreFields]
FROM [Src].[dbo].[MyTable] [MT_S]
JOIN [Src].[dbo].[FK_1] ON [MT_S].[FK_ID1] = [FK_1].[ID]
JOIN [Dest].[dbo].[FK_1] [FK_1_D] ON [FK_1].[Name] = [FK_1_D].[Name]
) [SRC] ON 1 = 0 
WHEN NOT MATCHED THEN
INSERT([DataField1],[FL_ID1],[LotsMoreFields])
VALUES ([DataField1],[FL_ID1],[LotsMoreFields])
OUTPUT [SRC].[SrcID],INSERTED.[ID],0,N'MyTable' INTO [Dest].[dbo].[ChangeTracking]([Src_ID],[Dest_ID],[AlreadyExists],[TableName]);

以上是关于动态SQL从表中执行大量行的主要内容,如果未能解决你的问题,请参考以下文章

从表中删除不会删除行

从表中随机选择行 - Python Pandas 读取 SQL

sql 使用Mysql中的ID从表中删除许多行

从表中随机选择行 - Python Pandas Read SQL

SQL 从表中选择并获取表名

Db2 SQL 根据大量数据选择排除行的行