亚洲综合原千岁中文字幕_国产精品99久久久久久久vr_无码人妻aⅴ一区二区三区浪潮_成人h动漫精品一区二区三

主頁 > 知識庫 > MSSQL批量插入數據優化詳細

MSSQL批量插入數據優化詳細

熱門標簽:400電話辦理泰安 安卡拉地圖標注app 我要地圖標注數量有限制嗎 家庭農場地圖標注名稱怎樣起名 電話機器人怎么代理商 互聯網電話外呼系統 電銷需要外呼系統嗎 零成本地圖標注賺錢 千呼電話機器人可以試用嗎

需求

 現在有一個需求是將10w條數據插入到MSSQL數據庫中,表結構如下,你會怎么做,你感覺插入10W條數據插入到MSSQL如下的表中需要多久呢?

或者你的批量數據是如何插入的呢?我今天就此問題做個探討。

壓測mvc的http接口看下數據

首先說下這里只是做個參照,來理解插入數據庫的性能狀況,與開篇的需求無半毛錢關系。

mvc接口代碼如下:

public bool Add(CustomerFeedbackEntity m)
    {
      using (var conn=Connection)
      {
        string sql = @"INSERT INTO [dbo].[CustomerFeedback]
                      ([BusType]
                      ,[CustomerPhone]
                      ,[BackType]
                      ,[Content]
                     )
                   VALUES
                      (@BusType
                      ,@CustomerPhone
                      ,@BackType
                      ,@Content
                      )";
        return conn.Execute(sql, m) > 0;
      }
    }

壓測的此mvc接口單條數據插入數據庫的聚合數據圖。

用例這樣的:5000個請求分500個線程執行post請求接口。

這個圖告訴我們,最慢的請求只用啦4毫秒。那么我們做個算法。

如開篇的需求來看,我們用最小的響應時間來計算。

那么插入10w條數據到數據庫需用時=100000*4毫秒,大致是6.67分鐘。那么我們奔著這個目標來做出插入方案。

最常見的insert做法

首先我們的工程師拿到需求后這樣寫啦段代碼,如下:

//執行數據條數
    int cnt = 10 * 10000;
    //要插入的數據
    CustomerFeedbackEntity m = new CustomerFeedbackEntity() { BusType = 1, CustomerPhone = "1888888888", BackType = 1, Content = "123123dagvhkfhsdjk肯定會撒嬌繁華的撒嬌防護等級劃分噶哈蘇德高房價盛大開放" };
    //第一種
    public void FristWay()
    {
      using (var conn = new SqlConnection(ConnStr))
      {
        conn.Open();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        StringBuilder sb = new StringBuilder();
        Console.WriteLine("從:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "開始循環執行:" + cnt + "條sql語句 ...");
        for (int i = 0; i = cnt; i++)
        {
          sb.Clear();
          sb.Append(@"INSERT INTO [dbo].[CustomerFeedback]
                      ([BusType]
                      ,[CustomerPhone]
                      ,[BackType]
                      ,[Content]
                     )
                   VALUES(");
          sb.Append(m.BusType);
          sb.Append(",'");
          sb.Append(m.CustomerPhone);
          sb.Append("',");
          sb.Append(m.BackType);
          sb.Append(",'");
          sb.Append(m.Content);
          sb.Append("')");
          using (SqlCommand cmd = new SqlCommand(sb.ToString(), conn))
          {
            cmd.CommandTimeout = 0;
            cmd.ExecuteNonQuery();
          }
        }
        Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "時,執行:" + cnt + "條sql語句完成 ! 耗時:" + sw.ElapsedMilliseconds + "毫秒。");
      }
    }

執行結果如下:

10w條數據,693906毫秒,11分鐘,有沒有感覺還行,或者還可以接受的。親們,我是吐血狀不說話,繼續寫,你們看MSSQL數據庫與.Net配合插入止于哪里?

點評下:

1、不停的創建與釋放sqlcommon對象,會有性能浪費。

2、不停的與數據庫建立連接,會有很大的性能損耗。

此2點還有執行結果告訴我們,此種方式不可取,即便這是我們最常見的數據插入方式。

那么我們針對以上兩點做優化,1、創建一次sqlcommon對象,只與數據庫建立一次連接。優化改造代碼如下:

public void SecondWay()
    {
      using (var conn = new SqlConnection(ConnStr))
      {
        conn.Open();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        StringBuilder sb = new StringBuilder();
        Console.WriteLine("從:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "開始循環拼接:" + cnt + "條sql語句 ...");
        for (int i = 0; i = cnt; i++)
        {
          sb.Append(@"INSERT INTO [dbo].[CustomerFeedback]
                      ([BusType]
                      ,[CustomerPhone]
                      ,[BackType]
                      ,[Content]
                     )
                   VALUES(");
          sb.Append(m.BusType);
          sb.Append(",'");
          sb.Append(m.CustomerPhone);
          sb.Append("',");
          sb.Append(m.BackType);
          sb.Append(",'");
          sb.Append(m.Content);
          sb.Append("')");
        }
        var result = sw.ElapsedMilliseconds;
        Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "時,循環拼接:" + cnt + "條sql語句完成 ! 耗時:" + result + "毫秒。");
        using (SqlCommand cmd = new SqlCommand(sb.ToString(), conn))
        {
          cmd.CommandTimeout = 0;
          Stopwatch sw1 = new Stopwatch();
          sw1.Start();
          Console.WriteLine("從:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "開始執行:" + cnt + "條sql語句 ...");
          cmd.ExecuteNonQuery();
          Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "時,執行:" + cnt + "條sql語句完成 ! 耗時:" + sw1.ElapsedMilliseconds + "毫秒。");
        }
      }
    }

執行結果如下:

呀,好奇怪啊,為什么跟上一個方案沒有多大區別呢?

首先我們看下拼接這么長的sql語句是怎么在數據庫中是怎么執行的。

1、查看數據庫的連接情況

select * from sysprocesses where dbid in (select dbid from sysdatabases where name='dbname')
--或者
SELECT * FROM
[Master].[dbo].[SYSPROCESSES] WHERE [DBID] IN ( SELECT 
  [DBID]
FROM 
  [Master].[dbo].[SYSDATABASES]
WHERE 
  NAME='dbname'
)

2、查看數據庫正在執行的sql語句

SELECT [Spid] = session_id ,
      ecid ,
      [Database] = DB_NAME(sp.dbid) ,
      [User] = nt_username ,
      [Status] = er.status ,
      [Wait] = wait_type ,
      [Individual Query] = SUBSTRING(qt.text,
                      er.statement_start_offset / 2,
                      ( CASE WHEN er.statement_end_offset = -1
                         THEN LEN(CONVERT(NVARCHAR(MAX), qt.text))
                            * 2
                         ELSE er.statement_end_offset
                       END - er.statement_start_offset )
                      / 2) ,
      [Parent Query] = qt.text ,
      Program = program_name ,
      hostname ,
      nt_domain ,
      start_time
  FROM  sys.dm_exec_requests er
      INNER JOIN sys.sysprocesses sp ON er.session_id = sp.spid
      CROSS APPLY sys.dm_exec_sql_text(er.sql_handle) AS qt
  WHERE  session_id > 50 -- Ignore system spids.
      AND session_id NOT IN ( @@SPID ) -- Ignore this current statement.
ORDER BY  1 ,

點評:雖然看似得到啦優化,其實與上一個解決方案的執行過程幾乎是一樣的,所以就不用多說什么啦。

利于MSSQL數據庫的用戶自定義表類型做優化
依舊先上代碼,或許這樣你才能對用戶自定義表類型產生興趣。

CREATE TYPE CustomerFeedbackTemp AS TABLE(
BusType int NOT NULL,
CustomerPhone varchar(40) NOT NULL,
BackType int NOT NULL,
Content nvarchar(1000) NOT NULL
)
public void ThirdWay()
    {
      Stopwatch sw = new Stopwatch();
      Stopwatch sw1 = new Stopwatch();
      DataTable dt = GetTable();
      using (var conn = new SqlConnection(ConnStr))
      {
        string sql = @"INSERT INTO[dbo].[CustomerFeedback]
                      ([BusType]
                      ,[CustomerPhone]
                      ,[BackType]
                      ,[Content]
                     ) select BusType,CustomerPhone,BackType,[Content] from @TempTb";
        using (SqlCommand cmd = new SqlCommand(sql, conn))
        {
          cmd.CommandTimeout = 0;
          SqlParameter catParam = cmd.Parameters.AddWithValue("@TempTb", dt);
          catParam.SqlDbType = SqlDbType.Structured;
          catParam.TypeName = "dbo.CustomerFeedbackTemp";
          conn.Open();
          Console.WriteLine("從:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "開始循環插入內存表中:" + cnt + "條數據 ...");
          sw.Start();
          for (int i = 0; i  cnt; i++)
          {
            DataRow dr = dt.NewRow();
            dr[0] = m.BusType;
            dr[1] = m.CustomerPhone;
            dr[2] = m.BackType;
            dr[3] = m.Content;
            dt.Rows.Add(dr);
          }
          Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "時,循環插入內存表:" + cnt + "條數據完成 ! 耗時:" + sw.ElapsedMilliseconds + "毫秒。");
          sw1.Start();
          if (dt != null  dt.Rows.Count != 0)
          {
            cmd.ExecuteNonQuery();
            sw.Stop();
          }
          Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "時,執行:" + cnt + "條數據的datatable的數據進數據庫 ! 耗時:" + sw1.ElapsedMilliseconds + "毫秒。");
        }
      }
    }

運行結果:

哇抓Q,不到2秒,不到2秒,怎么比每條4毫秒還快,不敢相信,是不是運行出問題啦。

再來一遍

再來一遍

是的你沒有看錯,10w條數據,不到2秒。是不是迫不及待的要知道為什么?迫不及待的想知道我們用到的用戶自定義表類型是什么?

用戶自定義表類型

首先類型大家應該很容易理解,像int,varchar,bit等都是類型,那么這個表類型是個毛線呢?

其實他就是用戶可以自己定義一個表結構然后把他當作一個類型。

創建自定義類型的詳細文檔:https://msdn.microsoft.com/zh-cn/library/ms175007.aspx

其次自定義類型也有一些限制,安全性:https://msdn.microsoft.com/zh-cn/library/bb522526.aspx

然后就是如何用這個類型,他的使用就是作為表值參數來使用的。

使用表值參數,可以不必創建臨時表或許多參數,即可向 Transact-SQL 語句或例程(如存儲過程或函數)發送多行數據。

表值參數與 OLE DB 和 ODBC 中的參數數組類似,但具有更高的靈活性,且與 Transact-SQL 的集成更緊密。 表值參數的另一個優勢是能夠參與基于數據集的操作。

Transact-SQL 通過引用向例程傳遞表值參數,以避免創建輸入數據的副本。 可以使用表值參數創建和執行 Transact-SQL 例程,并且可以使用任何托管語言從 Transact-SQL 代碼、托管客戶端以及本機客戶端調用它們。

優點

就像其他參數一樣,表值參數的作用域也是存儲過程、函數或動態 Transact-SQL 文本。 同樣,表類型變量也與使用 DECLARE 語句創建的其他任何局部變量一樣具有作用域。 可以在動態 Transact-SQL 語句內聲明表值變量,并且可以將這些變量作為表值參數傳遞到存儲過程和函數。

表值參數具有更高的靈活性,在某些情況下,可比臨時表或其他傳遞參數列表的方法提供更好的性能。 表值參數具有以下優勢:

首次從客戶端填充數據時,不獲取鎖。

提供簡單的編程模型。

允許在單個例程中包括復雜的業務邏輯。

減少到服務器的往返。

可以具有不同基數的表結構。

是強類型。

使客戶端可以指定排序順序和唯一鍵。

在用于存儲過程時像臨時表一樣被緩存。 從 SQL Server 2012 開始,對于參數化查詢,表值參數也被緩存。

限制

表值參數有下面的限制:

SQL Server 不維護表值參數列的統計信息。

表值參數必須作為輸入 READONLY 參數傳遞到 Transact-SQL 例程。 不能在例程體中對表值參數執行諸如 UPDATE、DELETE 或 INSERT 這樣的 DML 操作。

不能將表值參數用作 SELECT INTO 或 INSERT EXEC 語句的目標。 表值參數可以在 SELECT INTO 的 FROM 子句中,也可以在 INSERT EXEC 字符串或存儲過程中。

常見的BULK INSERT 數據集插入優化

public void FourWay()
    {

      Stopwatch sw = new Stopwatch();
      Stopwatch sw1 = new Stopwatch();
      DataTable dt = GetTable();
      using (SqlConnection conn = new SqlConnection(ConnStr))
      {
        SqlBulkCopy bulkCopy = new SqlBulkCopy(conn);
        bulkCopy.BulkCopyTimeout = 0;
        bulkCopy.DestinationTableName = "CustomerFeedback";
        bulkCopy.BatchSize = dt.Rows.Count;
        conn.Open();
        Console.WriteLine("從:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "開始循環插入內存表中:" + cnt + "條數據 ...");
        sw.Start();
        for (int i = 0; i  cnt; i++)
        {
          DataRow dr = dt.NewRow();
          dr[0] = m.BusType;
          dr[1] = m.CustomerPhone;
          dr[2] = m.BackType;
          dr[3] = m.Content;
          dt.Rows.Add(dr);
        }
        Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "時,循環插入內存表:" + cnt + "條數據完成 ! 耗時:" + sw.ElapsedMilliseconds + "毫秒。");
        sw1.Start();
        if (dt != null  dt.Rows.Count != 0)
        {
          bulkCopy.WriteToServer(dt);
          sw.Stop();
        }
        Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff") + "時,執行:" + cnt + "條數據的datatable的數據進數據庫 ! 耗時:" + sw1.ElapsedMilliseconds + "毫秒。");
      }

執行結果:

1秒之內完成,1秒之內完成,看完這個簡直要在1秒之內完成10w條數據的插入的節奏,逆天,逆天啊。

bulk insert詳解:https://msdn.microsoft.com/zh-cn/library/ms188365.aspx

專業的點評:

表值參數的使用方法與其他基于數據集的變量的使用方法相似;但是,頻繁使用表值參數將比大型數據集要快。 大容量操作的啟動開銷比表值參數大,與之相比,表值參數在插入數目少于 1000 的行時具有很好的執行性能。

重用的表值參數可從臨時表緩存中受益。 這一表緩存功能可比對等的 BULK INSERT 操作提供更好的伸縮性。 使用小型行插入操作時,可以通過使用參數列表或批量語句(而不是 BULK INSERT 操作或表值參數)來獲得小的性能改進。 但是,這些方法在編程上不太方便,并且隨著行的增加,性能會迅速下降。

表值參數在執行性能上與對等的參數陣列實現相當甚至更好。

總結

接下來是大家最喜歡的總結內容啦,內容有三,如下:

1、希望能關注我其他的文章。

2、博客里面有沒有很清楚的說明白,或者你有更好的方式,那么歡迎加入左上方的2個交流群,我們一起學習探討。

3、你可以忘記點贊加關注,但千萬不要忘記掃碼打賞哦。

下面是其他網友的補充:

你前面的插入,完全是拼字符串,沒有用到任何“參數”,每個語句SQL SERVER都要解析,沒有辦法緩存,當然慢了;你可以嘗試用用參數化插入,相信也是幾秒就可以插入完

大批量數據插入,首選SqlBulkCopy

標簽:新鄉 黃山 文山 東營 濱州 大同 池州 來賓

巨人網絡通訊聲明:本文標題《MSSQL批量插入數據優化詳細》,本文關鍵詞  MSSQL,批量,插入,數據,優化,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《MSSQL批量插入數據優化詳細》相關的同類信息!
  • 本頁收集關于MSSQL批量插入數據優化詳細的相關信息資訊供網民參考!
  • 推薦文章
    国产精品123| 欧美国产日韩久久久| 亚洲天堂在线播放| 麻豆系列 在线视频| 黄色短视频网站| 青青久久精品| 美女免费精品视频在线观看| 国产成人精品在线| 在线观看导航| 国产成人精品综合在线| 久久久成人影院| 99热热久久| 91麻豆tv| 国产视频一区在线| 日本伦理片网站| 日韩一级黄色| 欧美a免费| 欧美一级视频免费| 国产一区二区精品尤物| 欧美激情在线精品video| 午夜欧美福利| 色综合久久天天综合观看| 国产91精品一区| 成人高清视频免费观看| 久久精品免视看国产明星| 精品久久久久久综合网 | 日本伦理片网站| 一本高清在线| 中文字幕一区二区三区精彩视频 | 四虎影视久久久| 欧美国产日韩在线| 九九久久99| 精品国产三级a∨在线观看| 尤物视频网站在线观看| 亚洲精品久久久中文字| 美女免费黄网站| 高清一级片| 日本免费看视频| 99色视频在线观看| 国产视频久久久| 免费一级片在线观看| 二级特黄绝大片免费视频大片| 99久久精品国产片| 精品国产一区二区三区久| 国产精品自拍在线| 日韩中文字幕在线亚洲一区| 国产一级强片在线观看| 国产精品123| 国产一区二区精品尤物| 国产不卡福利| 国产精品1024永久免费视频| 免费的黄色小视频| 精品在线免费播放| 国产视频网站在线观看| 日韩在线观看视频网站| 日韩avdvd| 久久久久久久免费视频| 亚洲天堂免费观看| 天天做日日爱| 亚洲精品久久久中文字| 99色精品| 国产一区国产二区国产三区| 99热精品一区| 日韩一级精品视频在线观看| 欧美激情一区二区三区在线| 99色精品| 国产美女在线观看| 黄视频网站免费观看| 沈樵在线观看福利| 日韩中文字幕在线播放| 国产麻豆精品免费密入口| 国产一区二区精品| 美国一区二区三区| 尤物视频网站在线观看| 日韩一级精品视频在线观看| 四虎影视精品永久免费网站| 夜夜操天天爽| 99久久精品国产国产毛片| 在线观看导航| 日日日夜夜操| 韩国妈妈的朋友在线播放| 日韩中文字幕在线亚洲一区| 精品国产三级a∨在线观看| 日韩一级精品视频在线观看| 欧美夜夜骑 青草视频在线观看完整版 久久精品99无色码中文字幕 欧美日韩一区二区在线观看视频 欧美中文字幕在线视频 www.99精品 香蕉视频久久 | 麻豆系列 在线视频| 天天做人人爱夜夜爽2020| 精品视频在线观看视频免费视频| 免费国产在线观看| 欧美电影免费看大全| 国产一区二区精品尤物| 亚欧视频在线| 成人a大片高清在线观看| 免费国产在线观看| 91麻豆精品国产自产在线| 91麻豆国产级在线| 免费国产在线观看| 欧美大片a一级毛片视频| 国产原创视频在线| 日本伦理片网站| 精品在线免费播放| 夜夜操天天爽| 亚洲爆爽| 欧美激情在线精品video| 国产麻豆精品免费密入口| 欧美激情一区二区三区在线| 精品视频免费看| 91麻豆高清国产在线播放| 国产精品自拍在线| 国产一级强片在线观看| 久久国产影院| 四虎影视久久久| 黄视频网站免费观看| 国产伦理精品| 日韩中文字幕在线亚洲一区| 免费一级片在线观看| 四虎影视精品永久免费网站| 91麻豆精品国产自产在线| 天天做人人爱夜夜爽2020| 欧美a级成人淫片免费看| 国产一区免费观看| 999精品在线| 美国一区二区三区| 精品美女| 日日夜夜婷婷| 日本免费看视频| 精品国产一区二区三区免费| 国产成人啪精品| 青青久热| 精品国产香蕉在线播出| 欧美夜夜骑 青草视频在线观看完整版 久久精品99无色码中文字幕 欧美日韩一区二区在线观看视频 欧美中文字幕在线视频 www.99精品 香蕉视频久久 | 日韩中文字幕在线播放| 国产高清在线精品一区二区| 欧美另类videosbestsex视频| 成人高清护士在线播放| 麻豆网站在线免费观看| 青青青草影院| 国产视频一区二区在线观看| 国产成a人片在线观看视频| 国产一区二区精品久| 中文字幕97| 国产亚洲精品aaa大片| 欧美大片毛片aaa免费看| 国产成人啪精品| 精品国产一区二区三区久| 免费一级片在线观看| 国产伦久视频免费观看 视频 | 欧美a免费| 午夜欧美福利| 欧美激情一区二区三区视频| 成人a大片高清在线观看| 天天做人人爱夜夜爽2020| 一级女性大黄生活片免费| 91麻豆国产级在线| 尤物视频网站在线观看| 中文字幕97| 青青久热| 日本在线不卡免费视频一区| 91麻豆精品国产综合久久久| 亚洲精品影院久久久久久| 国产不卡福利| 国产伦久视频免费观看 视频 | 日韩avdvd| 日本特黄特色aaa大片免费| 国产一区二区精品久| 国产成人女人在线视频观看| 国产不卡福利| 欧美a级片视频| 国产一区二区精品尤物| 成人a级高清视频在线观看| 日韩在线观看视频黄| 中文字幕一区二区三区精彩视频 | 天天做日日干| 一级片片| 一本高清在线| 欧美日本韩国| 精品在线免费播放| 九九久久99| 欧美激情在线精品video| 久久99这里只有精品国产| 九九久久国产精品| 麻豆系列 在线视频| 麻豆系列 在线视频| 国产高清视频免费| 尤物视频网站在线| 精品视频在线看| 日本在线www| 高清一级片| 亚洲天堂免费观看| 国产a视频| 免费一级片在线观看| 国产韩国精品一区二区三区| 免费的黄色小视频| 久久国产影院| 久久99青青久久99久久| 日韩一级精品视频在线观看| 国产欧美精品| 日本久久久久久久 97久久精品一区二区三区 狠狠色噜噜狠狠狠狠97 日日干综合 五月天婷婷在线观看高清 九色福利视频 | 91麻豆高清国产在线播放| 亚洲精品影院久久久久久|