C#在MySQL大量數(shù)據(jù)下的高效讀取、寫入詳解
前言
C#操作MySQL大量數(shù)據(jù)最常見的操作便是 select 讀取數(shù)據(jù),然后在C#中對(duì)數(shù)據(jù)進(jìn)行處理, 完畢后再插入數(shù)據(jù)庫中。 簡而言之就 select -> process -> insert 三個(gè)步驟。 對(duì)于數(shù)據(jù)量小的情況下(百萬級(jí)別 or 幾百兆)可能
最多1個(gè)小時(shí)就處理完了。但是對(duì)于千萬級(jí)數(shù)據(jù)可能幾天,甚至更多。 那么問題來了,如何優(yōu)化??
第一步 解決讀取的問題
跟數(shù)據(jù)庫打交道的方式有很多,我來列舉下吧:
1. 【重武器-坦克大炮】使用重型ORM框架,比如 EF,NHibernat 這樣的框架。
2. 【輕武器-AK47】 使用 Dapper,PetaPoco 之類,單cs文件。靈活高效,使用簡單。居家越貨必備(我更喜歡PetaPoco :))
3. 【冷兵器?匕首?】使用原生的Connection、Command。 然后寫原生的SQL語句。。
分析:
【重武器】在我們這里肯定直接被PASS, 他們應(yīng)該被用在大型項(xiàng)目中。
【輕武器】 Dapper,PetaPoco 看過源碼你會(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ù)處理.... } }
哈哈,怎么樣,代碼非常原始,還是使用索引來取數(shù)據(jù),很容易出錯(cuò)。 當(dāng)然一切為了性能咱都忍了
第二步 數(shù)據(jù)處理
其實(shí)這一步,根據(jù)你的業(yè)務(wù)需要,代碼肯定不一, 不過無非是一些 字符串處理 , 類型轉(zhuǎn)換 的操作,這時(shí)候就是考驗(yàn)?zāi)愕腃#基礎(chǔ)功底的時(shí)候了。 以及如何高效編寫正則表達(dá)式。。。
具體代碼也沒法寫啊 ,先看完 CLR via C# 在來跟我討論吧 ,O(∩_∩)O哈哈哈~ 跳過。。。。
第三部 數(shù)據(jù)插入
如何批量插入才最高效呢? 有同學(xué)會(huì)說, 使用 事務(wù) 啊,BeginTransaction, 然后EndTransaction。 恩,這個(gè)的確可以提高插入效率。 但是還有更加高效的方法,那就是合并insert語句。
那么怎么合并呢?
insert into table (f1,f2) values(1,'sss'),values(2,'bbbb'),values(3,'cccc');
就是把values后面的全部用逗號(hào),鏈接起來,然后一次性執(zhí)行 。
當(dāng)然不能一次性提交個(gè)100MB的SQL執(zhí)行,MySQL服務(wù)器對(duì)每次執(zhí)行命令的長度是有限制的。 通過 MySQL服務(wù)器端的 max_allowed_packet 屬性可以查看, 默認(rèn)是 1MB
咱們來看看偽代碼吧
//使用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(); //此處設(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 * 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)化后的高效查詢、插入就完成了。
總結(jié)
總結(jié)下來,無非2個(gè)關(guān)鍵技術(shù)點(diǎn), DataReader、SQL合并, 都是一些老的技術(shù)啦。其實(shí),上面的代碼只能稱得上高效, 但是, 卻非常的不優(yōu)雅。以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家能有所幫助,如果有疑問大家可以留言交流。
上一篇:利用C#操作WMI指南
欄 目:C#教程
下一篇:C#中數(shù)據(jù)的傳遞以及ToolStripProgressBar
本文標(biāo)題:C#在MySQL大量數(shù)據(jù)下的高效讀取、寫入詳解
本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/6166.html
您可能感興趣的文章
- 01-10C#實(shí)現(xiàn)將窗體固定在顯示器的左上角且不能移動(dòng)的方法
- 01-10C#實(shí)現(xiàn)在Form里面內(nèi)嵌dos窗體的方法
- 01-10C#中查找Dictionary中的重復(fù)值的方法
- 01-10C#實(shí)現(xiàn)在啟動(dòng)目錄創(chuàng)建快捷方式的方法
- 01-10關(guān)于nancy中的身份驗(yàn)證
- 01-10C#編程自學(xué)之類和對(duì)象
- 01-10C#創(chuàng)建不規(guī)則窗體的4種方式詳解
- 01-10C#實(shí)現(xiàn)讀取DataSet數(shù)據(jù)并顯示在ListView控件中的方法
- 01-10C#中yield用法使用說明
- 01-10C#編程自學(xué)之流程控制語句


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻 器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文