一个视图查出来15亿数据。(视图包含有10个视图,一个视图有100个表。一个表有150万行数据,)
跟据字段中的QQ号。分别插入150个表中。我写了一个存储过程。一个小时才30万数据。
SET QUOTED_IDENTIFIER OFF  
GO
SET ANSI_NULLS ON  
GOCREATE PROCEDURE get_mycursor
AS --定义游标mycursor
DECLARE mycursor CURSOR FOR   --使用游标的对象(QQ表)
SELECT QQNum,Nick,Age,Gender,Auth,QunNum FROM group1_100    --打开游标
OPEN mycursor   DECLARE  
@QQNum VARCHAR(50),
@Nick VARCHAR(50),
@Age VARCHAR(50),
@Gender VARCHAR(50),
@Auth VARCHAR(50),
@QunNum VARCHAR(50),
@sql VARCHAR(500)  --将游标向下移1行,获取的数据放入之前定义的变量@QQNum,@Nick,@Age,@Gender,@Auth,@QunNum 中
FETCH NEXT FROM mycursor INTO @QQNum,@Nick,@Age,@Gender,@Auth,@QunNum   --判断是否成功获取数据
WHILE @@fetch_status=0   
 BEGIN
    
  SET @sql=''--判断QQ是不是七位数的还是八位的
IF(LEN(@QQNum)>7)   
BEGIN
--如果是八位数以上的。跟据条件动态拼成插入某表的sql语句
SET @sql=' INSERT newlist'+SUBSTRING(@QQNum,1,LEN(@QQNum)-7)+' (QQNum,Nick,Age,Gender,Auth,QunNum)  
VALUES( '+''''+@QQNum+''''+','+''''+@Nick+''''+','+''''+@Age+''''+','+''''+@Gender+''''+','+''''+@Auth+''''+','+''''+@QunNum+''''+')'
END
ELSE
BEGIN
--低于七位数,直接拼成插入newlist0这个表
SET @sql=' INSERT newlist0 (QQNum,Nick,Age,Gender,Auth,QunNum)  
VALUES( '+''''+@QQNum+''''+','+''''+@Nick+''''+','+''''+@Age+''''+','+''''+@Gender+''''+','+''''+@Auth+''''+','+''''+@QunNum+''''+')'
END
--运行运态语句
EXEC(@sql);  FETCH NEXT FROM mycursor INTO @QQNum,@Nick,@Age,@Gender,@Auth,@QunNum --将游标向下移1行
 END
 
--关闭游标
 CLOSE mycursor   --删除游标   
 DEALLOCATE mycursor
GO
SET QUOTED_IDENTIFIER OFF  
GO
SET ANSI_NULLS ON  
GO 

解决方案 »

  1.   

    游标很慢的,速度差不多.大致看了一下你的insert语句,应该可以直接使用insert...select...的,多加一个where条件就行.
      

  2.   

    如果直接用insert .... select .... 的话就查150次。每一次是15亿数据。。
      

  3.   

    首先,你最好使用高版本的数据库,特别是2008以后。然后使用分区表(05以后才出现),分区表可以实现并行插入,像你这种数据量,如果业务允许,可能分999个区都可以(999个分区是2008最大分区数)。这个很重要,代表你同时做999(这个数量只是举例而已)个插入动作。
    然后,在插入时禁用表中所有索引和不必要的触发器,等插入完再启用。同时插入时数据库的恢复模式改成大容量日志(可以在插入时才改)。
    第三,千万不要用游标,你的游标不把数据库弄死已经非常了得了。
    第四,看看可以不可以使用到BULK INSERT这类动作,这类操作是目前为止插入速度最快的操作。基本上没有更快的了(除非科研级别的数据库)
      

  4.   


    不能用游标,循环一次游标相当于执行一条sql语句的效率,会进行很多表扫描
    直接用语句
     INSERT  newlist(a,b,d,e) select a,b,c,d from group1_100  where LEN(QQNum)>7
     
     INSERT  newlist0(a,b,d,e) select a,b,c,d from group1_100  where LEN(QQNum)<=7
      

  5.   

    前面DBA_Huangzj的说法有道理,个人觉得两点:
    1、不使用游标;
    2、大数据量批量导出时,防止数据库做完整性检查以及索引和日志的创建,因为本身是导出操作,不担心数据的丢失和数据的正确性,日志和完整性已没有必要。
       所以先去掉索引和其他的约束,另外,不清楚sql server里面的是否有停用日志记录的,呵呵。
       然后,就是等数据导出完成后,再把索引这些加上。
      

  6.   

    怎么chrome浏览器里没法编辑呢?
    补充一句,上面那个停用日志是对整个数据库起作用,慎用慎用。
      

  7.   


    CREATE PROCEDURE get_mycursor
    AS --低于七位数,直接拼成插入newlist0这个表
    INSERT Into newlist0
    Select QQNum,Nick,Age,Gender,Auth,QunNum FROM group1_100 Where LEN(QQNum)<=7   --定义游标mycursor
    DECLARE mycursor CURSOR FOR    --使用游标的对象(QQ表)
    SELECT Distinct SUBSTRING(QQNum,1,LEN(QQNum)-7) QQNum FROM group1_100 Where LEN(QQNum)> 7   --打开游标
    OPEN mycursor    DECLARE   
    @QQNum VARCHAR(50)
    @sql VARCHAR(500) --将游标向下移1行,获取的数据放入之前定义的变量@QQNum,@Nick,@Age,@Gender,@Auth,@QunNum 中
    FETCH NEXT FROM mycursor INTO @QQNum --判断是否成功获取数据
    WHILE @@fetch_status==0   
    BEGIN    
    SET @sql='' --如果是八位数以上的。跟据条件动态拼成插入某表的sql语句
    SET @sql=' INSERT newlist'+@QQNum+' (QQNum,Nick,Age,Gender,Auth,QunNum)   
    Select QQNum,Nick,Age,Gender,Auth,QunNum FROM group1_100 Where SUBSTRING(QQNum,1,LEN(QQNum)-7)=  '''+@QQNum+'''' --运行运态语句
    EXEC(@sql); FETCH NEXT FROM mycursor INTO @QQNum --将游标向下移1行
    END
     
    --关闭游标
    CLOSE mycursor    --删除游标   
    DEALLOCATE mycursor GO
      

  8.   

    日志是不能停用的,就算简单模式或者大容量日志模式都是会记录日志,只是它的截断速度很快而已。你的这个插入操作本来就不可能在OLTP中做,不然并发性几乎达不到2位数。