《Mysql必讀C#如何在海量數據下的高效讀取寫入MySQL》要點:
本文介紹了Mysql必讀C#如何在海量數據下的高效讀取寫入MySQL,希望對您有用。如果有疑問,可以聯系我們。
MYSQL入門前提
MYSQL入門由于工作的原因,經常必要對海量數據進行處理,做的數據爬蟲相關,動輒千萬級別的數據,單表幾十個G都是都是家常便飯.? 主要開發語言是C#,數據庫使用的是MySQL.
MYSQL入門最常見的操作就是 select 讀取數據,然后在C#中對數據進行處理, 完畢后再插入數據庫中.? 簡而言之就 select -> process -> insert三個步驟. 對于數據量小的情況下(百萬級別 or 幾百兆)可能最多1個小時就處理完了.但是對于千萬級數據可能幾天,甚至更多. 那么問題來了,如何優化??
MYSQL入門
MYSQL入門?(數據庫的一覽,有圖有真相)
MYSQL入門第一步 辦理讀取的問題
MYSQL入門跟數據庫打交道的方式有很多,我來列舉下吧:
MYSQL入門1. 【重武器-坦克大炮】使用重型ORM框架,好比EF,NHibernat 這樣的框架.
2. 【輕武器-AK47】 使用Dapper,PetaPoco之類,單cs文件.靈活高效,使用簡單.居家越貨必備(我更喜歡PetaPoco :))
3. 【冷兵器?匕首?】使用原生的Connection、Command. 然后寫原生的SQL語句..
MYSQL入門闡發:
MYSQL入門【重兵器】在我們這里肯定直接被PASS, 他們應該被用在大型項目中.?
MYSQL入門【輕兵器】Dapper,PetaPoco 看過源碼你會發現用到了反射,雖然使用IL和緩存技術,但是還是會影響讀取效率,PASS
好吧那就只有使用匕首,原生SQL走起, 利用DataReader 進行高效讀取,并且使用索引取數據(更快),而不是列名.
大概的代碼如下:
MYSQL入門
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);
//這里做數據處理....
}
}
MYSQL入門哈哈,怎么樣,代碼非常原始,還是使用索引來取數據,很容易出錯.? 當然一切為了性能咱都忍了
MYSQL入門第二步 數據處置
MYSQL入門其實這一步,根據你的業務必要,代碼肯定不一, 不過無非是一些字符串處理,類型轉換的操作,這時候就是考驗你的C#基礎功底的時候了. 以及如何高效編寫正則表達式...
MYSQL入門具體代碼也沒法寫啊 ,先看完CLR via C# 在來跟我討論吧 ,O(∩_∩)O哈哈哈~ 跳過....
MYSQL入門第三部 數據插入
MYSQL入門如何批量插入才最高效呢?? 有同學會說, 使用事務啊,BeginTransaction, 然后EndTransaction. 恩,這個的確可以提高插入效率. 但是還有更加高效的辦法,那就是合并insert語句.
MYSQL入門那么怎么合并呢?
MYSQL入門
insert into table (f1,f2) values(1,'sss'),values(2,'bbbb'),values(3,'cccc');
MYSQL入門便是把values后面的全部用逗號,鏈接起來,然后一次性執行 .
MYSQL入門當然不克不及一次性提交個100MB的SQL執行,MySQL服務器對每次執行命令的長度是有限制的. 通過 MySQL服務器端的max_allowed_packet? 屬性可以查看, 默認是1MB
MYSQL入門咱們來看看偽代碼吧
MYSQL入門
//使用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 頭
}
}
}
MYSQL入門好了,到這里 大概的優化后的高效查詢、插入就完成了.?
MYSQL入門結語
MYSQL入門總結下來,無非2個關鍵技術點,DataReader、SQL合并,都是一些老的技術啦.
MYSQL入門其實,上面的代碼只能稱得上 高效 , 但是, 卻非常的不優雅...甚至難看...
MYSQL入門那那么問題來了?? 如何進行重構呢? 通過重構抽象出一個可用的類,而不必關心字符串拼接這些亂七八糟的東西,支持多線程合并寫入,最年夜限度提高寫入IO,? 我們在下一篇文章中再來談談.
《Mysql必讀C#如何在海量數據下的高效讀取寫入MySQL》是否對您有啟發,歡迎查看更多與《Mysql必讀C#如何在海量數據下的高效讀取寫入MySQL》相關教程,學精學透。維易PHP學院為您提供精彩教程。