Heim  >  Artikel  >  Backend-Entwicklung  >  Lösung für die langsame Einfügungsgeschwindigkeit oder den Datenverlust von Sqlserver bei großen Datenmengen

Lösung für die langsame Einfügungsgeschwindigkeit oder den Datenverlust von Sqlserver bei großen Datenmengen

高洛峰
高洛峰Original
2017-01-13 15:43:371850Durchsuche

Mein Gerät fügt 2.000 Daten pro Sekunde in die Datenbank ein, und die beiden Geräte fügen insgesamt 4.000 Daten ein. Beim direkten Einfügen mit der Einfügeanweisung im Programm können zwei Geräte insgesamt etwa 2.800 Daten gleichzeitig einfügen Die Daten gehen verloren. Nach dem Testen vieler Methoden wurden zwei Lösungen mit offensichtlichen Auswirkungen ermittelt:

Methode 1: Verwenden Sie die SQL Server-Funktion:

1 in strings Verwenden Sie die Funktion, um Daten in die Speichertabelle einzufügen, und kopieren Sie dann die Speichertabellendaten in die einzufügende Tabelle.

2. Ändern Sie das Format der kombinierten Zeichen: '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', Jede Datenzeile ist durch „;“ getrennt und jedes Feld ist durch „|“ getrennt.

3. Funktion schreiben:

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,&#39;&#39;+@Data+&#39;&#39;,@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,&#39;&#39;+@Data+&#39;&#39;,@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,&#39;&#39;+@Data+&#39;&#39;,@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,&#39;&#39;+@Data+&#39;&#39;,@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,&#39;&#39;+@Data+&#39;&#39;,@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,&#39;&#39;+@Data+&#39;&#39;,@Alarm,@AlmLev,cast(@substr2 as datetime),GETDATE())
        END
    SET @ii=@ii+1
  END
  -----二次循环结束
  END  
 SET @i=@i+1    
 END  
END  
RETURN  
END

Ergebnisanzeige:

insert into [mytable] select * from [dbo].[fun_funcname](&#39;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&#39;,&#39;;&#39;,&#39;|&#39;);

Methode 2: Verwenden Sie BULK INSERT

select * from [mytable] ;
Der erste Vorgang zum Einfügen großer Datenmengen: Verwenden Sie Bulk, um Dateidaten in die Datenbank einzufügen

SQL-Code

Datenbank erstellen

Testtabelle erstellen

CREATE DATABASE [db_mgr]
GO

Testdaten füllen

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

Aktivieren Sie die gespeicherte Prozedur xp_cmdshell (nach dem Öffnen bestehen Sicherheitsrisiken)

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

Verwenden Sie bcp, um Formatdateien zu exportieren:

EXEC sp_configure &#39;show advanced options&#39;, 1;
RECONFIGURE;EXEC sp_configure &#39;xp_cmdshell&#39;, 1;
EXEC sp_configure &#39;show advanced options&#39;, 0;
RECONFIGURE;

Verwenden Sie bcp, um Datendateien zu exportieren:

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

Löschen Sie die Daten in der Tabelle

EXEC master..xp_cmdshell &#39;BCP db_mgr.dbo.T_Student out C:/student.data -f C:/student_fmt.xml -T&#39;

Verwenden Sie die Bulk-Insert-Anweisung, um die Datendatei stapelweise zu importieren:

truncate table db_mgr.dbo.T_Student

Beispiel für die Verwendung von OPENROWSET (BULK):

BULK INSERT db_mgr.dbo.T_Student
FROM &#39;C:/student.data&#39;
WITH
(
  FORMATFILE = &#39;C:/student_fmt.xml&#39;
)
T_Student-Tabelle muss bereits vorhanden sein

Beispiel für die Verwendung von OPENROWSET (BULK):

INSERT INTO db_mgr.dbo.T_Student(F_Code, F_Name) SELECT F_Code, F_Name
FROM OPENROWSET(BULK N&#39;C:/student.data&#39;, FORMATFILE=N&#39;C:/student_fmt.xml&#39;) AS new_table_name
TT-Tabelle muss nicht vorhanden sein

Weitere Lösungen für SQL Server langsame Einfügungsgeschwindigkeit bei großem Datenvolumen oder Datenverlust. Für Artikel zu Lösungen beachten Sie bitte die chinesische PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn