提早將DataReader.Close還是會把資料傳完

在用DataReader讀資料時,如果取回的資料有100筆,但因為需求關係,程式判斷到,符合某個條件時,就不再繼續Read下去,直接把DataReader給Close掉.但這麼做還是會把剩下的資料全部傳回來.

  最近在看微軟的MSDN,看到其中有一段是之前寫程式沒注意到的地方,就是我們在用DataReader讀資料時,如果取回的資料有100筆,但因為需求關係,程式判斷到,符合某個條件時,就不再繼續Read下去,直接把DataReader給Close掉.但這麼做還是會把剩下的資料全部傳回來.

Ex :


cmd.CommandText = "select * from testtable";

conn.Open();

sdr = cmd.ExecuteReader();

while (sdr.Read())
{
    if ((int)sdr["id"] == 1)
    {
        break;
    }

    //Do Something….
}

sdr.Close();

所以MSDN裡卻不建議這麼做,需在Close之前,將Command.Cancel(),原文如下:

====================第一篇====================

Cancel Pending Data

When you call the Close method, the method does not return until all the remaining data has been fetched. If you know you have pending data when you want to close your DataReader, you can call the Cancel method before you call Close to tell the server to stop sending data.

This approach does not always result in a performance improvement, because Cancel is not guaranteed to make the server stop sending data. Control information is still exchanged after the call to Cancel, and the control information may or may not be interleaved with leftover data. Therefore, before you restructure your code to call Cancel before Close, test Cancel to learn if it actually helps in your particular scenario and to learn if you really need the extra performance at the expense of readability.

Note    If you need output parameters, do not call Close until you have retrieved the output parameters. After you retrieve the output parameters, you can then call Close.

====================第二篇====================

當您透過使用 SqlDataReader 以使用關聯的 SqlConnection 做任何其他用途時,必須明確呼叫 Close 方法。

Close 方法會為輸出參數、傳回值和 RecordsAffected 填入值,增加它所花費的時間來關閉 SqlDataReader (用來處理大量或複雜的查詢)。如果查詢影響的傳回值與資料錄數量並不顯著,則先呼叫相關聯之 SqlCommand 物件的 Cancel 方法,再呼叫 Close 方法,可降低它關閉 SqlDataReader 所花費的時間。

====================結 束====================

  主要的意思就是,就算我們Close,資料庫還是會持續傳資料回來,並不會停止,所以在Close之前,要先呼叫DBCommand.Cancel(),才能再呼叫DBDataReader.Close()

 

我試著重現這個問題,確實,在MS SQL會有這樣的現象,如果沒有呼叫Cancel,在Close後,確實資料還是持續回來.

我在本機建了一個Table

Table Name : TestTable,

Column :

ID(int)

Gid(nvarchar50)

Gid2(nvarchar50)

Gid3(nvarchar50)

ID從0~99999,三個Gid就塞入Guid,所以有十萬筆資料在裡面.共25.203MB

沒有呼叫Cancel,耗時約0.225秒

有呼叫Cancel,耗時約0.00074秒

Ex :


cmd.CommandText = "select * from testtable";

conn.Open();

sdr = cmd.ExecuteReader();

while (sdr.Read())
{
    if ((int)sdr["id"] == 1)
    {
        break;
    }

    //Do Something….
}

cmd.Cancel();

sdr.Close();

“但”,我在Oracle上測試時,就沒有這樣的現象,有沒有呼叫Cancel都是一樣的效能(樣本數27,532筆26.886MB),所以Oracle上沒差,其它的DB就不知道了.

 

FYI :

SqlDataReader.Close 方法

黑暗大也寫了一篇一樣的,寫的也比我好,有興趣的人也可以看一下:

KB-當心SqlDataReader.Close時的額外資料傳輸量