2012年3月15日 星期四

SqlDataAdapter.UpdateBatchSize


今天客戶反應說匯入程式的效能不好,
他說匯入四千多筆資料要 3 分鐘左右,
個人是覺得四千多筆資料 3 分鐘應該是可以接受的範圍吧?
不過客戶說覺得不好也只能調整看看了!
客戶查了資料發現,其實資料寫入 Local 的 DataTable 其實花不到 3 秒鐘,
所以大部分的時間應該是卡在從 DataTable 寫入 DB 的時間,
個人是覺得這個我好像沒甚麼好調整的吧?
不過在我本機測試了一下,
發現不管我怎麼測,通通都沒有超過 1000 毫秒?
這樣表示其實也不是寫入 DB 的速度慢囉?
那麼是客戶端網路環境的關係嗎?

在無聊亂看的時候發現有 SqlDataAdapter.UpdateBatchSize 這個參數可以調整,
這個參數是來調整一次要一筆寫入還是整批寫入,
然後可以調整一批的數量的參數。
不過匯入程式是一次把四千多筆資料一次丟上去,
然後呼叫 SqlDataAdapter.Update 來寫入DB的,
這樣他不會一次一整批寫入嗎?
查了半天,沒找到哪邊有提到他的預設值是甚麼?
直接 Debug 看他的值才發現預設是 1 ㄟ
只怪我把世界想的太美好了!
查了一下 SqlDataAdapter.UpdateBatchSize 要怎麼用,
說明裡面有說:



將其設為大於 1 的值時,與 SqlDataAdapter 相關聯的所有命令都必須將其 UpdatedRowSource 屬性設為 None OutputParameters。否則會擲回例外狀況。


不過我照著寫

SqlDataAdapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;



卻會有錯誤訊息!
所以我最後只有加寫了一行

SqlDataAdapter.UpdateBatchSize = 10000;



目前看起來單筆修改跟整批匯入的 Update 都沒有問題,
似乎是有比較快一點,接下來就看客戶那邊有沒有變快囉!

2012年2月7日 星期二

C# 如何移除未知名稱的事件 - BarButtonItem.Click


上次有寫過,
如果傳進來的 BindingSource 有 PositionChanged 的事件的時候就去觸發它!
請參閱【C# 如何強制驅動物件的事件?】。

這次不一樣的是,如果傳進來的 BarButtonItem 有 ItemClick 的事件的話,
我要將它移除,然後重新掛上自己的事件。
為什麼會有這樣的需求呢?
因為在底層的查詢按鈕直接將事件寫在 ItemClick 上面了,
而我想要拿這個按鈕來用卻又不想要執行底層的程式,
所以我需要將原來 delegate 的移除之後再重新掛上我的 ItemClick 程式。
緣由說明完畢啦!接下來就要實做了,
依照上次【C# 如何強制驅動物件的事件?】的做法居然得不到 FieldInfo !
google 了很久,後來在 DevExpress 的討論區裡面看到一個範例,
雖然是 VB 有點看不太懂,
後來我照著翻譯成 C# 之後也是可以跑的,
程式碼如下:

2012年1月30日 星期一

C# 擴充方法 - Extensions

因為有需要要把 DataTable 的資料倒出來到 csv 檔案裡面去,
想要有很簡易的使用方式,
於是乎就參考到了 擴充方法 (C# 程式設計手冊) ,
程式寫完之後我就可以直接用 DataTable.ExportCSV 來使用我新增的方法了!
如下圖所示:



可以直接這樣點出來是不是很棒!
那這樣的程式該怎麼寫呢?

2012年1月27日 星期五

C# Threading Finial

上一篇文章(C# Threading - 使用 WaitHandle)有提到
【主執行緒要等副執行緒查完之後才會更新介面上的資訊感覺很鳥】,
所以今天我要來改善這個問題,
基本上我想到的解法就是把原本查詢按鈕按下去裡面的程式改成另一個獨立的函式,
然後用副執行緒去呼叫,
所以原來的 btnThreadingQuery_Click 就變成下面這樣啦!

private void btnThreadingQuery_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(QueryMain));
}

原來裡面的程式就被我移到了 QueryMain() 去了,然後妳還記得嗎?
在第一篇文章(C# 多緒程式該怎麼寫? - Threading)的時候,
我曾經說過副執行緒不可以直接去處理 UI 相關的東西,
所以原本我們在裡面有去控制按鈕跟滑鼠游標也要依照第一篇的觀念去修改,
全部的修改內容如下:

2012年1月23日 星期一

C# Threading - 使用 WaitHandle

上一篇文章(C# 多緒程式該怎麼寫? - Threading)說到,
副執行緒還再跑的時候按鈕卻已經浮起來了,
然後總執行時間也不太對,
因為那個總執行時間並不包含副執行緒跑完的時間!
沒想到這麼快我就找到了解決的方法了!
誤打誤撞的找到了 WaitHandle 的範例,
於是就照著範例改了一下程式,
範例如下:
先宣告 WaitHandle 的陣列

    // Define an array with two AutoResetEvent WaitHandles.
    static WaitHandle[] waitHandles = new WaitHandle[]
    {
        new AutoResetEvent(false),
        new AutoResetEvent(false)
    };

然後使用方式如下:

ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask),         
        waitHandles[0]);
ThreadPool.QueueUserWorkItem(new WaitCallback(DoTask), 
        waitHandles[1]);
WaitHandle.WaitAll(waitHandles);

然後在副執行緒的最後要補上一行,
將傳進來的 AutoResetEvent 呼叫 Set(),
範例上是這樣寫的,如下:

are.Set();

看起來好像不難,所以我就先照著改一下囉!

2012年1月19日 星期四

C# 多緒程式該怎麼寫? - Threading

之前為了需要寫了一個多緒的程式,
為了怕忘記,所以寫了一個簡單的程式來紀錄一下多緒的程式該怎麼寫,
這樣以後自己才有的參考。

簡單的說就是兩個按鈕,一個是單緒的查詢、一個是多緒的查詢,
兩個查詢的內容基本上是一樣的,先查詢一個筆數很多的資料表,
然後再查一個筆數比較少的資料表。

程式執行的畫面如下:


由於單緒的程式會等第一個查詢完了之後才查第二個資料表,
所以妳會發現第二個查詢的時間其實就等於全部查詢的時間;
但是如果是多緒的程式的話妳就會發現第二個查詢的筆數跟時間會比較快出來,
而全部的執行時間其實只有1毫秒,因為這個只是去呼叫程式的時間,
並不是全部查詢完之後的時間。
(突然發現毫秒的字錯了!!!)

先來看看單緒的程式的寫法吧!

C# 計算執行時間的物件 - CalcTime

為了計算執行時間方便使用,
所以寫了一個計算時間的物件,
沒甚麼特別的,所以直接分享程式碼吧!

CalcTime 物件的使用方式如下:
第一步,先建立物件:

CalcTime calcTime = new CalcTime();


第二步,程式執行完了直接呼叫 Duration(),會直接丟出執行的毫秒的字串。

calcTime.Duration();


如果需要重新計算的話,直接呼叫 Restart() 就會重設了,不需要重新建立 CalcTime 物件。

calcTime.Restart();


CalcTime 物件的程式碼如下:

public class CalcTime
{
    TimeSpan tsStart;
    public CalcTime()
    {
        tsStart = new TimeSpan(DateTime.Now.Ticks);
    }
   
    public void Restart()
    {
        tsStart = new TimeSpan(DateTime.Now.Ticks);
    }

    public string Duration()
    {
        TimeSpan tsEnd = new TimeSpan(DateTime.Now.Ticks);
        TimeSpan ts = tsStart.Subtract(tsEnd).Duration();
        return ts.Milliseconds.ToString() + "毫秒";           
    }
}