获取数百万条记录太慢了

Posted

技术标签:

【中文标题】获取数百万条记录太慢了【英文标题】:Fetching Millions Records going too slow 【发布时间】:2018-07-30 10:47:29 【问题描述】:

我正在尝试使用带有 Fetching 的聚集索引复制其他表中的 6000 万条记录。但是在 2000 万张唱片之后,它变得太慢了。我不知道我该怎么做。任何人都可以帮助我吗?这是我的计时。

1000000 百万分钟:1 2000000 百万分钟:0 3000000 百万分钟:0 40000 亿分钟:2 5000000 百万分钟:2 6000000 百万分钟:1 7000000 百万分钟:0 8000000 百万分钟:1 9000000 百万分钟:0 10000000 百万分钟:1 11000000 百万分钟:0 12000000 百万分钟:1 13000000 百万分钟:1 14000000 百万分钟:0 15000000 百万分钟:1 16000000 百万分钟:1 17000000 百万分钟:1 18000000 百万分钟:0 19000000 百万分钟:1 20000000 百万分钟:3 21000000 百万分钟:3 22000000 百万分钟:4 23000000 百万分钟:5 24000000 百万分钟:4 25000000 百万分钟:4 26000000 百万分钟:4 27000000 百万分钟:4 28000000 百万分钟:5 29000000 百万分钟:5 30000000 百万分钟:5 31000000 百万分钟:6 32000000 百万分钟:7 33000000 百万分钟:7 34000000 百万分钟:8 35000000 百万分钟:8 36000000 百万分钟:9 37000000 百万分钟:8 38000000 百万分钟:10 39000000 百万分钟:10 40000000 百万分钟:11 41000000 百万分钟:11 42000000 百万分钟:11 43000000 百万分钟:12 44000000 百万分钟:11 45000000 百万分钟:12 46000000 百万分钟:12 47000000 百万分钟:14 48000000 百万分钟:13 49000000 百万分钟:13 50000000 百万分钟:14 51000000 百万分钟:15 52000000 百万分钟:14 53000000 百万分钟:16 54000000 百万分钟:18 55000000 百万分钟:18 56000000 百万分钟:20 57000000 百万分钟:19 58000000 百万分钟:21 59000000 百万分钟:19

    
declare 
        @RecNo Int
      , @RecCount Int

      , @RecordST nvarchar(max)
      , @str_date datetime
      , @end_date datetime;

    Set @RecNo = 0
    select @RecCount = 1000000

         While 1 = 1 
           Begin


                set @str_date = getdate();
                Insert Into dbo.test2(
                   ap_id                                
                  ,lipt_id                          
                  ,li_cntr                                            
                 )
            select 
                     ap_id                              
                    ,lipt_id                            
                    ,li_cntr                                                
                 from dbo.test 
             order by  ap_id, lipt_id, li_cntr

             offset @RecNo rows
             fetch next @RecCount rows only;
             if  @@ROWCOUNT = 0
               break              

             Set @RecNo += 1000000;

             set @end_date = GETDATE() ;
             set @RecordST = cast(@RecNo as nvarchar(max)) + ' Million Min:'+cast(DATEDIFF(MINUTE,@str_date,@end_date) as nvarchar(max))
             RAISERROR(@RecordST,0,0) WITH NOWAIT            

  end

【问题讨论】:

如何在复制之前删除索引,然后在复制之后再次创建它? 由于使用了偏移量,偏移量越高,插入的方法就会越慢。您可能想阅读this old SO answer。如果源表的主键是数字,那么使用该方法的速度将比通过偏移量更一致。 OFFSETFETCH 将逐渐变慢,因为每次迭代都必须重新计算偏移量。如果您按聚集索引键的范围而不是行号分页进行批处理,您将获得线性性能。 感谢您的回答。如何按聚集索引键的范围而不是行号分页进行批处理?你能解释一下吗? TOP(@RecCount) ... WHERE plip_ap_id > @LastValueProcessed ORDER BY plip_ap_id 每次都应该具有相同的性能特征。这要求您的表具有可以从中查找的唯一键。对于复合键,它变得更加烦人。 【参考方案1】:

首先,您需要删除所有约束,例如唯一性、PK 等。这是现有表中每个插入的瓶颈。

其次,如果您向表中插入的记录比现在多得多,那么您可以使用SELECT INTO 语句而不是INSERT 来提高性能。但请记住,SELECT INTO 创建了一个新表,因此您需要考虑如何附加以前存在的记录。

最后但并非最不重要的一点是,您可以使用循环并批量插入 1M 记录。

【讨论】:

我想使用SELECT INTO 语句,但我不知道该语句是否使用Tempdb?因为我的硬盘没有足够的空间来存储 60M 记录。 如果我在插入后定义约束有什么问题吗? 这取决于约束,但在很多情况下您不会遇到问题

以上是关于获取数百万条记录太慢了的主要内容,如果未能解决你的问题,请参考以下文章

从固定宽度的平面文件获取数百万条记录到 SQL 2000

mysql 如何实现 count 超过1000条记录 就返回 1000

在数据表中显示数百万条记录

数百万条记录的增量更新,索引与连接

删除数百万条记录 oracle [关闭]

多连接数百万条记录的优化查询需要建议