1

我正在尝试向表中插入大量记录。这是场景:

  1. SQL Server 2008(数据库为 2005)

  2. 目标表有一个聚集索引 (PK)。该字段应该是一个身份,但是数据库的开发人员(我们无法更改它,因为它会影响程序)将其创建为一个整数。每次程序需要向表中添加一行时,请查看最大 id(historyno在这种情况下)并求和。

  3. 当我们需要同时插入大量记录时,这会影响我们的性能,因此我们创建了一个流程来AKT_ES_CampTool_TempHist在生产时间之外从临时表 () 中插入行。

  4. 问题是,在一小时内,它只插入 8K 行。考虑到我们需要插入超过 120K,我们用完了几个小时。

我们使用的代码如下。请,如果有人有任何改进它的想法,将不胜感激。

DECLARE             @HistNo         AS INT

WHILE EXISTS (SELECT * FROM AKT_ES_CampTool_TempHist WHERE Inserted = 0)
BEGIN

    SELECT  @HistNo=MIN(HistoryNo) FROM AKT_ES_CampTool_TempHist WHERE Inserted = 0

    INSERT INTO NOVADB.dbo.niHist   (
        HistoryNo,ObjectType,ObjectNo,SubNo,ReferenceNo, 
        Time,Type,Priority,Collector,Code,
        Action,RemainingAmount,Obliterated,SubType,ActSegment,
        Data,FreetextData,quantity
                                        )
        SELECT      
        (SELECT  max(historyNo)+1 
        FROM    NOVADB..niHist),ObjectType,ObjectNo,SubNo,ReferenceNo,
        Time,Type,Priority,Collector,Code,
        Action,RemainingAmount,Obliterated,SubType,ActSegment,
        Data,FreetextData,quantity 
        FROM        AKT_ES_CampTool_TempHist 
        WHERE       HistoryNo=@HistNo

        UPDATE  AKT_ES_CampTool_TempHist
        SET     Inserted=1
        WHERE   HistoryNo=@HistNo

END
4

3 回答 3

2

显然,正确的答案是将 historyNo 列更改为一个标识,但是由于您不能这样做,为什么不在整个集合中使用 ROW_NUMBER 来获得一个递增的数字以添加到 prev max historyNo 中呢?

然后你可以将插入更改为

DECLARE  @OldMaxHistNo  AS INT
SELECT @OldMaxHistNo = MAX(historyNo) FROM NOVADB..niHist

INSERT INTO NOVADB.dbo.niHist   (
    HistoryNo,ObjectType,ObjectNo,SubNo,ReferenceNo, 
    Time,Type,Priority,Collector,Code,
    Action,RemainingAmount,Obliterated,SubType,ActSegment,
    Data,FreetextData,quantity
                                    )
    SELECT      
    @OldMaxHistNo+ ROW_NUMBER() OVER(ORDER BY ObjectNo)
    FROM    NOVADB..niHist),ObjectType,ObjectNo,SubNo,ReferenceNo,
    Time,Type,Priority,Collector,Code,
    Action,RemainingAmount,Obliterated,SubType,ActSegment,
    Data,FreetextData,quantity 
    FROM        AKT_ES_CampTool_TempHist 
    WHERE       Inserted = 0

    UPDATE  AKT_ES_CampTool_TempHist
    SET     Inserted=1

可能必须在执行此操作时锁定事务中的表

于 2013-09-25T11:11:58.730 回答
1

您可以使用由 Rownumber() 生成的新 HistoryNo 并使用来自 NOVADB..niHist 的 max(historyNo) 更改应插入临时表中的数据。

SELECT  ROW_NUMBER() OVER (Order by ID) as NEW_HistoryNo , * 
into #tmp
FROM AKT_ES_CampTool_TempHist 
WHERE Inserted = 0
ORDER BY HistoryNo

Update #tmp set NEW_HistoryNo=NEW_HistoryNo + (SELECT  max(historyNo) FROM    NOVADB..niHist)

INSERT INTO NOVADB.dbo.niHist   (
        HistoryNo,ObjectType,ObjectNo,SubNo,ReferenceNo, 
        Time,Type,Priority,Collector,Code,
        Action,RemainingAmount,Obliterated,SubType,ActSegment,
        Data,FreetextData,quantity )                                 )
SELECT      
        NEW_HistoryNo,ObjectType,ObjectNo,SubNo,ReferenceNo,
        Time,Type,Priority,Collector,Code,
        Action,RemainingAmount,Obliterated,SubType,ActSegment,
        Data,FreetextData,quantity
from #tmp

Update AKT_ES_CampTool_TempHist  set Inserted = 1
from #tmp
Where #tmp.HistoryNo=AKT_ES_CampTool_TempHist.HistoryNo and AKT_ES_CampTool_TempHist.Inserted = 0

Drop Table #tmp
于 2013-09-25T11:05:44.703 回答
0

您永远不应该使用您用于分配索引的 max+1 策略。假设您不能使用身份和主表,并且您没有使用最新版本的 sql server - 基于身份字段创建影子表并使用它来生成序列号

IE

create table AKT_ES_CampTool_Shadow
(
  id int identity(1234,1) not null -- replacing 1234 with a value based on max+1
, dummy varchar(1) null
)

然后生成一个 id——比 max+1 便宜——没有锁定问题

create proc AKT_ES_CampTool_idgen(@newid output)
(
  declare @newid int
  begin tran

  insert into dbo.AKT_ES_CampTool_Shadow (dummy) values ('') 
  select @newid = scope_id()
  rollback  
)

你没有说 AKT_ES_CampTool_TempHist 有多大。如果它很大,您可能会在那里遇到性能问题(尤其是如果“插入”字段上没有索引)

您可以首先创建一个包含相关列的表 var。

declare @TempHist table
(
  HistNo int
, inserted int
, etc.

primary key(...)
)

然后使用单个插入查询填充 @TempHist。如果您没有适合此表的 PK,请使用生成的 RowID s PK

现在,您可以循环遍历此表而不会导致锁争用。只需从@TempHist 中选择前1 名,并在完成处理后从@TempHist 中删除相应的行。

您不会使用游标,也不会进行大批量操作

于 2013-09-25T20:01:29.237 回答