濮阳杆衣贸易有限公司

主頁(yè) > 知識(shí)庫(kù) > C#如何在海量數(shù)據(jù)下的高效讀取寫(xiě)入MySQL

C#如何在海量數(shù)據(jù)下的高效讀取寫(xiě)入MySQL

熱門(mén)標(biāo)簽:如何選擇優(yōu)質(zhì)的外呼系統(tǒng) 清遠(yuǎn)申請(qǐng)400電話(huà) 沈陽(yáng)智能外呼系統(tǒng)供應(yīng)商 谷歌地圖標(biāo)注位置圖解 東莞外呼企業(yè)管理系統(tǒng) 手機(jī)外呼系統(tǒng)違法嗎 桂林云電銷(xiāo)機(jī)器人收費(fèi) 地圖簡(jiǎn)圖標(biāo)注 南通電銷(xiāo)外呼系統(tǒng)哪家強(qiáng)

前提

由于工作的原因,經(jīng)常需要對(duì)海量數(shù)據(jù)進(jìn)行處理,做的數(shù)據(jù)爬蟲(chóng)相關(guān),動(dòng)輒千萬(wàn)級(jí)別的數(shù)據(jù),單表幾十個(gè)G都是都是家常便飯。  主要開(kāi)發(fā)語(yǔ)言是C#,數(shù)據(jù)庫(kù)使用的是MySQL。

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

 (數(shù)據(jù)庫(kù)的一覽,有圖有真相)

第一步 解決讀取的問(wèn)題

跟數(shù)據(jù)庫(kù)打交道的方式有很多,我來(lái)列舉下吧:

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

分析:

【重武器】在我們這里肯定直接被PASS, 他們應(yīng)該被用在大型項(xiàng)目中。 

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

using (var conn = new MySqlConnection('Connection String...'))
{
  conn.Open();
  //此處設(shè)置讀取的超時(shí),不然在海量數(shù)據(jù)時(shí)很容易超時(shí)
  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`';
  //設(shè)置命令的執(zhí)行超時(shí)
  rcmd.CommandTimeout = 99999999;
  var myData = rcmd.ExecuteReader();

  while (myData.Read())
  {
    var f1= myData.GetInt32(0);
    var f2= myData.GetString(1);
    //這里做數(shù)據(jù)處理....
  }
}

哈哈,怎么樣,代碼非常原始,還是使用索引來(lái)取數(shù)據(jù),很容易出錯(cuò)。  當(dāng)然一切為了性能咱都忍了

第二步 數(shù)據(jù)處理

其實(shí)這一步,根據(jù)你的業(yè)務(wù)需要,代碼肯定不一, 不過(guò)無(wú)非是一些字符串處理,類(lèi)型轉(zhuǎn)換的操作,這時(shí)候就是考驗(yàn)?zāi)愕腃#基礎(chǔ)功底的時(shí)候了。 以及如何高效編寫(xiě)正則表達(dá)式。。。

具體代碼也沒(méi)法寫(xiě)啊 ,先看完CLR via C# 在來(lái)跟我討論吧 ,O(∩_∩)O哈哈哈~ 跳過(guò)。。。。

第三部 數(shù)據(jù)插入

如何批量插入才最高效呢?  有同學(xué)會(huì)說(shuō), 使用事務(wù)啊,BeginTransaction, 然后EndTransaction。 恩,這個(gè)的確可以提高插入效率。 但是還有更加高效的方法,那就是合并insert語(yǔ)句。

那么怎么合并呢?

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


就是把values后面的全部用逗號(hào),鏈接起來(lái),然后一次性執(zhí)行 。

當(dāng)然不能一次性提交個(gè)100MB的SQL執(zhí)行,MySQL服務(wù)器對(duì)每次執(zhí)行命令的長(zhǎng)度是有限制的。 通過(guò) MySQL服務(wù)器端的max_allowed_packet  屬性可以查看, 默認(rèn)是1MB

咱們來(lái)看看偽代碼吧

 //使用StringBuilder高效拼接字符串
 var sqlBuilder = new StringBuilder();
 //添加insert 語(yǔ)句的頭
 string sqlHeader = 'insert into table1 (`f1`,`f2`) values';
 sqlBuilder.Append(sqlHeader);
 using (var conn = new MySqlConnection('Connection String...'))
 {
   conn.Open();
   //此處設(shè)置讀取的超時(shí),不然在海量數(shù)據(jù)時(shí)很容易超時(shí)
   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`';
   //設(shè)置命令的執(zhí)行超時(shí)
   rcmd.CommandTimeout = 99999999;
   var myData = rcmd.ExecuteReader();
   while (myData.Read())
   {
     var f1 = myData.GetInt32(0);
     var f2 = myData.GetString(1);
     //這里做數(shù)據(jù)處理....
     sqlBuilder.AppendFormat('({0},'{1}'),', f1,AddSlash(f2));
     if (sqlBuilder.Length >= 1024 * 1024)//當(dāng)然這里的1MB length的字符串并不等于 1MB的Packet。。。我知道:)
     {
       insertCmd.Execute(sqlBuilder.Remove(sqlBuilder.Length-1,1).ToString())//移除逗號(hào),然后執(zhí)行
       sqlBuilder.Clear();//清空
       sqlBuilder.Append(sqlHeader);//在加上insert 頭
     }
   }
}

好了,到這里 大概的優(yōu)化后的高效查詢(xún)、插入就完成了。 

結(jié)語(yǔ)

總結(jié)下來(lái),無(wú)非2個(gè)關(guān)鍵技術(shù)點(diǎn),DataReader、SQL合并,都是一些老的技術(shù)啦。

其實(shí),上面的代碼只能稱(chēng)得上 高效 , 但是, 卻非常的不優(yōu)雅。。。甚至難看。。。

那那么問(wèn)題來(lái)了?  如何進(jìn)行重構(gòu)呢? 通過(guò)重構(gòu)抽象出一個(gè)可用的類(lèi),而不必關(guān)心字符串拼接這些亂七八糟的東西,支持多線程合并寫(xiě)入,最大限度提高寫(xiě)入IO,  我們?cè)谙乱黄恼轮性賮?lái)談?wù)劇?/p>

您可能感興趣的文章:
  • C#如何連接MySQL數(shù)據(jù)庫(kù)
  • C#連接MySQL操作詳細(xì)教程
  • C#實(shí)現(xiàn)MySQL命令行備份和恢復(fù)
  • C#連接MySQL的兩個(gè)簡(jiǎn)單代碼示例
  • C#連接mysql的方法【基于vs2010】
  • C#在MySQL大量數(shù)據(jù)下的高效讀取、寫(xiě)入詳解
  • c#幾種數(shù)據(jù)庫(kù)的大數(shù)據(jù)批量插入(SqlServer、Oracle、SQLite和MySql)
  • C#中調(diào)用MySQL存儲(chǔ)過(guò)程的方法
  • C#連接mysql數(shù)據(jù)庫(kù)完整實(shí)例
  • C#實(shí)現(xiàn)操作MySql數(shù)據(jù)層類(lèi)MysqlHelper實(shí)例
  • c# 向MySQL添加數(shù)據(jù)的兩種方法

標(biāo)簽:湖州 重慶 常德 內(nèi)蒙古 天津 臨沂 成都 貴州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《C#如何在海量數(shù)據(jù)下的高效讀取寫(xiě)入MySQL》,本文關(guān)鍵詞  如,何在,海量,數(shù)據(jù),下,的,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《C#如何在海量數(shù)據(jù)下的高效讀取寫(xiě)入MySQL》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于C#如何在海量數(shù)據(jù)下的高效讀取寫(xiě)入MySQL的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章
    图木舒克市| 灌云县| 临高县| 仁布县| 尚义县| 浑源县| 湟源县| 柯坪县| 红安县| 武宁县| 大港区| 九江市| 平凉市| 福泉市| 宁波市| 古浪县| 克山县| 永登县| 深州市| 泸定县| 武功县| 中西区| 荃湾区| 长垣县| 绩溪县| 上饶市| 桐柏县| 成都市| 梁山县| 惠来县| 上杭县| 七台河市| 克什克腾旗| 平远县| 科技| 大悟县| 玉田县| 资中县| 奇台县| 正镶白旗| 腾冲县|