设为首页 收藏本站
查看: 982|回复: 0

[经验分享] Sql server 大数据量插入速度慢或丢失数据解决办法

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-6-13 10:00:13 | 显示全部楼层 |阅读模式
问题描述:我的设备每秒2000条数据插入数据库,2个设备总共4000条,当在程序里面直接用insert语句插入时,两个设备同时插入大概总共能插入约2800条左右,数据丢失约1200条左右,找了好多解决方法,整理了两种效果比较明显的解决办法:

第一种:使用Sql Server函数:

1.将数据组合成字串,使用函数将数据插入内存表,后将内存表数据复制到要插入的表。

2.组合成的字符换格式:'111|222|333|456,7894,7458|0|1|2014-01-01 12:15:16;1111|2222|3333|456,7894,7458|0|1|2014-01-01 12:15:16',每行数据中间用“;”隔开,每个字段之间用“|”隔开。

3.编写函数:



    CREATE FUNCTION [dbo].[fun_funcname](@str VARCHAR(max),@splitchar CHAR(1),@splitchar2 CHAR(1))   
    --定义返回表      
    RETURNS  @t TABLE(MaxValue float,Phase int,SlopeValue float,Data varchar(600),Alarm int,AlmLev int,GpsTime datetime,UpdateTime datetime) AS         
    /*           
    author:hejun li      
    create date:2014-06-09      
    */        
    BEGIN        
            
    DECLARE @substr VARCHAR(max),@substr2 VARCHAR(max)  
    --申明单个接收值   
    declare @MaxValue float,@Phase int,@SlopeValue float,@Data varchar(8000),@Alarm int,@AlmLev int,@GpsTime datetime   
    SET @substr=@str        
    DECLARE @i INT,@j INT,@ii INT,@jj INT,@ijj1 int,@ijj2 int,@m int,@mm int     
    SET @j=LEN(REPLACE(@str,@splitchar,REPLICATE(@splitchar,2)))-LEN(@str)--获取分割符个数        
    IF @j=0        
        BEGIN        
          --INSERT INTO @t VALUES (@substr,1) --没有分割符则插入整个字串     
          set @substr2=@substr;  
          set @ii=0  
          SET @jj=LEN(REPLACE(@substr2,@splitchar2,REPLICATE(@splitchar2,2)))-LEN(@substr2)--获取分割符个数  
              WHILE  @ii<=@jj  
                    BEGIN  
                        if(@ii<@jj)  
                            begin  
                                SET @mm=CHARINDEX(@splitchar2,@substr2)-1 --获取分割符的前一位置  
                                    
                                if(@ii=0)  
                                    set @MaxValue=cast(LEFT(@substr2,@mm) as float)  
                                else if(@ii=1)  
                                    set @Phase=cast(LEFT(@substr2,@mm) as int)  
                                else if(@ii=2)  
                                    set @SlopeValue=cast(LEFT(@substr2,@mm) as float)  
                                else if(@ii=3)  
                                    set @Data=cast(LEFT(@substr2,@mm) as varchar)  
                                else if(@ii=4)  
                                    set @Alarm=cast(LEFT(@substr2,@mm) as int)  
                                else if(@ii=5)  
                                    set @AlmLev=cast(LEFT(@substr2,@mm) as int)  
                                else if(@ii=6)  
                                    INSERT INTO @t VALUES(@MaxValue,@Phase,@SlopeValue,''+@Data+'',@Alarm,@AlmLev,cast(@substr2 as datetime),GETDATE())  
      
                                SET @substr2=RIGHT(@substr2,LEN(@substr2)-(@mm+1)) --去除已获取的分割串,得到还需要继续分割的字符串  
                            end  
                        else  
                            BEGIN  
                                --当循环到最后一个值时将数据插入表  
                                INSERT INTO @t VALUES(@MaxValue,@Phase,@SlopeValue,''+@Data+'',@Alarm,@AlmLev,cast(@substr2 as datetime),GETDATE())  
                                                
                            END   
                    --END  
                    SET @ii=@ii+1  
                END  
        END        
    ELSE        
    BEGIN        
     SET @i=0        
     WHILE @i<=@j        
     BEGIN        
       IF(@i<@j)        
       BEGIN        
        SET @m=CHARINDEX(@splitchar,@substr)-1 --获取分割符的前一位置  
           
        --INSERT INTO @t VALUES(LEFT(@substr,@m),@i+1)   
        -----二次循环开始  
        --1.线获取要二次截取的字串  
        set @substr2=(LEFT(@substr,@m));  
        --2.初始化二次截取的起始位置  
        set @ii=0  
        --3.获取分隔符个数  
        SET @jj=LEN(REPLACE(@substr2,@splitchar2,REPLICATE(@splitchar2,2)))-LEN(@substr2)--获取分割符个数  
        WHILE  @ii<=@jj  
            BEGIN  
                if(@ii<@jj)  
                    begin  
                        SET @mm=CHARINDEX(@splitchar2,@substr2)-1 --获取分割符的前一位置  
                           
                        if(@ii=0)  
                            set @MaxValue=cast(LEFT(@substr2,@mm) as float)  
                        else if(@ii=1)  
                            set @Phase=cast(LEFT(@substr2,@mm) as int)  
                        else if(@ii=2)  
                            set @SlopeValue=cast(LEFT(@substr2,@mm) as float)  
                        else if(@ii=3)  
                            set @Data=cast(LEFT(@substr2,@mm) as varchar)  
                        else if(@ii=4)  
                            set @Alarm=cast(LEFT(@substr2,@mm) as int)  
                        else if(@ii=5)  
                            set @AlmLev=cast(LEFT(@substr2,@mm) as int)  
                        else if(@ii=6)  
                            INSERT INTO @t VALUES(@MaxValue,@Phase,@SlopeValue,''+@Data+'',@Alarm,@AlmLev,cast(@substr2 as datetime),GETDATE())  
      
                        SET @substr2=RIGHT(@substr2,LEN(@substr2)-(@mm+1)) --去除已获取的分割串,得到还需要继续分割的字符串  
                    end  
                else  
                    BEGIN  
                        --当循环到最后一个值时将数据插入表  
                        INSERT INTO @t VALUES(@MaxValue,@Phase,@SlopeValue,''+@Data+'',@Alarm,@AlmLev,cast(@substr2 as datetime),GETDATE())  
            
                    END   
            --END  
            SET @ii=@ii+1  
        END  
        -----二次循环结束  
        SET @substr=RIGHT(@substr,LEN(@substr)-(@m+1)) --去除已获取的分割串,得到还需要继续分割的字符串        
       END        
      ELSE        
       BEGIN  
        --INSERT INTO @t VALUES(@substr,@i+1)--对最后一个被分割的串进行单独处理   
        -----二次循环开始  
        --1.线获取要二次截取的字串  
        set @substr2=@substr;  
        --2.初始化二次截取的起始位置  
        set @ii=0  
        --3.获取分隔符个数  
        SET @jj=LEN(REPLACE(@substr2,@splitchar2,REPLICATE(@splitchar2,2)))-LEN(@substr2)--获取分割符个数  
        WHILE  @ii<=@jj  
            BEGIN  
                if(@ii<@jj)  
                    begin  
                        SET @mm=CHARINDEX(@splitchar2,@substr2)-1 --获取分割符的前一位置  
                        if(@ii=0)  
                            set @MaxValue=cast(LEFT(@substr2,@mm) as float)  
                        else if(@ii=1)  
                            set @Phase=cast(LEFT(@substr2,@mm) as int)  
                        else if(@ii=2)  
                            set @SlopeValue=cast(LEFT(@substr2,@mm) as float)  
                        else if(@ii=3)  
                            set @Data=cast(LEFT(@substr2,@mm) as varchar)  
                        else if(@ii=4)  
                            set @Alarm=cast(LEFT(@substr2,@mm) as int)  
                        else if(@ii=5)  
                            set @AlmLev=cast(LEFT(@substr2,@mm) as int)  
                        else if(@ii=6)  
                            INSERT INTO @t VALUES(@MaxValue,@Phase,@SlopeValue,''+@Data+'',@Alarm,@AlmLev,cast(@substr2 as datetime),GETDATE())  
      
                        SET @substr2=RIGHT(@substr2,LEN(@substr2)-(@mm+1)) --去除已获取的分割串,得到还需要继续分割的字符串  
                    end  
                else  
                    BEGIN  
                        --当循环到最后一个值时将数据插入表  
                        INSERT INTO @t VALUES(@MaxValue,@Phase,@SlopeValue,''+@Data+'',@Alarm,@AlmLev,cast(@substr2 as datetime),GETDATE())  
      
                    END   
            SET @ii=@ii+1  
        END  
        -----二次循环结束  
       END         
     SET @i=@i+1         
     END        
    END        
            
    RETURN         
    END  


4.调用函数语句:


    insert into [mytable] select * from [dbo].[fun_funcname]('111|222|333|456,7894,7458|0|1|2014-01-01 12:15:16;1111|2222|3333|456,7894,7458|0|1|2014-01-01 12:15:16',';','|');  


5.结果展示:


    select * from [mytable] ;  

SouthEast.jpg




第二种:使用BULK INSERT

--大数据量插入第一种操作,使用Bulk将文件数据插入数据库

--Sql代码


-- 创建数据库


    CREATE DATABASE [db_mgr]   
    GO   
    --创建测试表  
    USE db_mgr   
    CREATE TABLE dbo.T_Student(   
        F_ID [int] IDENTITY(1,1) NOT NULL,   
        F_Code varchar(10) ,   
        F_Name varchar(100) ,   
        F_Memo nvarchar(500) ,   
        F_Memo2 ntext ,   
        PRIMARY KEY  (F_ID)   
    )   
    GO  


--填充测试数据



    Insert Into T_Student(F_Code, F_Name, F_Memo, F_Memo2) select   
    'code001', 'name001', 'memo001', '备注' union all select   
    'code002', 'name002', 'memo002', '备注' union all select   
    'code003', 'name003', 'memo003', '备注' union all select   
    'code004', 'name004', 'memo004', '备注' union all select   
    'code005', 'name005', 'memo005', '备注' union all select   
    'code006', 'name006', 'memo006', '备注'  


--开启xp_cmdshell存储过程(开启后有安全隐患)



    EXEC sp_configure 'show advanced options', 1;   
    RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;   
    EXEC sp_configure 'show advanced options', 0;   
    RECONFIGURE;  


--使用bcp导出格式文件:



    EXEC master..xp_cmdshell 'BCP db_mgr.dbo.T_Student format nul -f C:/student_fmt.xml -x -c -T'   


--使用bcp导出数据文件:



    EXEC master..xp_cmdshell 'BCP db_mgr.dbo.T_Student out C:/student.data -f C:/student_fmt.xml -T'   


-- 将表中数据清空



    truncate table db_mgr.dbo.T_Student   


--使用Bulk Insert语句批量导入数据文件:



    BULK INSERT db_mgr.dbo.T_Student   
    FROM 'C:/student.data'   
    WITH   
    (   
        FORMATFILE = 'C:/student_fmt.xml'   
    )  


--使用OPENROWSET(BULK)的例子:-- T_Student表必须已存在



    INSERT INTO db_mgr.dbo.T_Student(F_Code, F_Name) SELECT F_Code, F_Name   
    FROM OPENROWSET(BULK N'C:/student.data', FORMATFILE=N'C:/student_fmt.xml') AS new_table_name   


--使用OPENROWSET(BULK)的例子:-- tt表可以不存在


    SELECT F_Code, F_Name INTO db_mgr.dbo.tt   
    FROM OPENROWSET(BULK N'C:/student.data', FORMATFILE=N'C:/student_fmt.xml') AS new_table_name   



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-20521-1-1.html 上篇帖子: SqlServer字段说明查询 下篇帖子: SQL Sever 2008配置工具中过程调用失败解决方法 server
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表