激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|數據庫技術|

服務器之家 - 數據庫 - Mysql - C#如何在海量數據下的高效讀取寫入MySQL

C#如何在海量數據下的高效讀取寫入MySQL

2020-07-05 16:45花生!~~ Mysql

這篇文章主要介紹了C#如何在海量數據下的高效讀取寫入MySQL的相關資料,需要的朋友可以參考下

前提

由于工作的原因,經常需要對海量數據進行處理,做的數據爬蟲相關,動輒千萬級別的數據,單表幾十個G都是都是家常便飯。  主要開發語言是C#,數據庫使用的是MySQL

最常見的操作便是 select 讀取數據,然后在C#中對數據進行處理, 完畢后再插入數據庫中。  簡而言之就 select -> process -> insert三個步驟。 對于數據量小的情況下(百萬級別 or 幾百兆)可能最多1個小時就處理完了。但是對于千萬級數據可能幾天,甚至更多。 那么問題來了,如何優化??

C#如何在海量數據下的高效讀取寫入MySQL

 (數據庫的一覽,有圖有真相)

第一步 解決讀取的問題

跟數據庫打交道的方式有很多,我來列舉下吧:

1. 【重武器-坦克大炮】使用重型ORM框架,比如EF,NHibernat 這樣的框架。
2. 【輕武器-AK47】 使用Dapper,PetaPoco之類,單cs文件。靈活高效,使用簡單。居家越貨必備(我更喜歡PetaPoco :))
3. 【冷兵器?匕首?】使用原生的Connection、Command。 然后寫原生的SQL語句。。

分析:

【重武器】在我們這里肯定直接被PASS, 他們應該被用在大型項目中。 

【輕武器】Dapper,PetaPoco 看過源碼你會發現用到了反射,雖然使用IL和緩存技術,但是還是會影響讀取效率,PASS
好吧那就只有使用匕首,原生SQL走起, 利用DataReader 進行高效讀取,并且使用索引取數據(更快),而不是列名。
大概的代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using (var conn = new MySqlConnection('Connection String...'))
{
  conn.Open();
  //此處設置讀取的超時,不然在海量數據時很容易超時
  var c = new MySqlCommand('set net_write_timeout=9999999; set net_read_timeout=9999999', conn);
  c.ExecuteNonQuery();
 
  MySqlCommand rcmd = new MySqlCommand();
  rcmd.Connection = conn;
  rcmd.CommandText = @'SELECT `f1`,`f2` FROM `table1`';
  //設置命令的執行超時
  rcmd.CommandTimeout = 99999999;
  var myData = rcmd.ExecuteReader();
 
  while (myData.Read())
  {
    var f1= myData.GetInt32(0);
    var f2= myData.GetString(1);
    //這里做數據處理....
  }
}

哈哈,怎么樣,代碼非常原始,還是使用索引來取數據,很容易出錯。  當然一切為了性能咱都忍了

第二步 數據處理

其實這一步,根據你的業務需要,代碼肯定不一, 不過無非是一些字符串處理,類型轉換的操作,這時候就是考驗你的C#基礎功底的時候了。 以及如何高效編寫正則表達式。。。

具體代碼也沒法寫啊 ,先看完CLR via C# 在來跟我討論吧 ,O(∩_∩)O哈哈哈~ 跳過。。。。

第三部 數據插入

如何批量插入才最高效呢?  有同學會說, 使用事務啊,BeginTransaction, 然后EndTransaction。 恩,這個的確可以提高插入效率。 但是還有更加高效的方法,那就是合并insert語句。

那么怎么合并呢?

?
1
insert into table (f1,f2) values(1,'sss'),values(2,'bbbb'),values(3,'cccc');

就是把values后面的全部用逗號,鏈接起來,然后一次性執行 。

當然不能一次性提交個100MB的SQL執行,MySQL服務器對每次執行命令的長度是有限制的。 通過 MySQL服務器端的max_allowed_packet  屬性可以查看, 默認是1MB

咱們來看看偽代碼吧

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//使用StringBuilder高效拼接字符串
 var sqlBuilder = new StringBuilder();
 //添加insert 語句的頭
 string sqlHeader = 'insert into table1 (`f1`,`f2`) values';
 sqlBuilder.Append(sqlHeader);
 using (var conn = new MySqlConnection('Connection String...'))
 {
   conn.Open();
   //此處設置讀取的超時,不然在海量數據時很容易超時
   var c = new MySqlCommand('set net_write_timeout=9999999; set net_read_timeout=9999999', conn);
   c.ExecuteNonQuery();
 
   MySqlCommand rcmd = new MySqlCommand();
   rcmd.Connection = conn;
   rcmd.CommandText = @'SELECT `f1`,`f2` FROM `table1`';
   //設置命令的執行超時
   rcmd.CommandTimeout = 99999999;
   var myData = rcmd.ExecuteReader();
   while (myData.Read())
   {
     var f1 = myData.GetInt32(0);
     var f2 = myData.GetString(1);
     //這里做數據處理....
     sqlBuilder.AppendFormat('({0},'{1}'),', f1,AddSlash(f2));
     if (sqlBuilder.Length >= 1024 * 1024)//當然這里的1MB length的字符串并不等于 1MB的Packet。。。我知道:)
     {
       insertCmd.Execute(sqlBuilder.Remove(sqlBuilder.Length-1,1).ToString())//移除逗號,然后執行
       sqlBuilder.Clear();//清空
       sqlBuilder.Append(sqlHeader);//在加上insert 頭
     }
   }
}

好了,到這里 大概的優化后的高效查詢、插入就完成了。 

結語

總結下來,無非2個關鍵技術點,DataReader、SQL合并,都是一些老的技術啦。

其實,上面的代碼只能稱得上 高效 , 但是, 卻非常的不優雅。。。甚至難看。。。

那那么問題來了?  如何進行重構呢? 通過重構抽象出一個可用的類,而不必關心字符串拼接這些亂七八糟的東西,支持多線程合并寫入,最大限度提高寫入IO,  我們在下一篇文章中再來談談。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 九九热视频免费 | 欧美成人精品一区 | 久色porn | 成人福利在线视频 | 中国产一级毛片 | 精品久久久一 | 91网址在线观看 | 日本一区二区不卡在线 | 国产精品欧美久久久久一区二区 | 亚洲啪啪 | 色淫网站免费视频 | 国产午夜亚洲精品午夜鲁丝片 | 俄罗斯16一20sex牲色另类 | 免费观看一级淫片 | 成年人高清视频在线观看 | 欧美一级做性受免费大片免费 | 一区二区三区四区国产 | 香蕉秀 | 美女福利视频国产 | 国产免费黄色 | 中文字幕在线观看视频一区 | 99久久久精品视频 | 久久亚洲精品国产一区 | 真人一级毛片免费 | 成人羞羞视频在线观看免费 | 老司机一级毛片 | 国产日产精品一区四区介绍 | 亚洲操比视频 | 最新亚洲国产 | 精品午夜影院 | 色女生影院 | 日本成人午夜视频 | 久久久99精品视频 | 亚洲人片在线观看 | 三级国产三级在线 | 免费一级毛片在线播放视频老 | 91福利免费观看 | 亚洲视频在线观看免费视频 | 久久久久免费精品 | 久久国产一二三 | 久久亚洲精品久久国产一区二区 |