iT邦幫忙

1

C# SqlDataAdapter Timeout問題

  • 分享至 

  • xImage

下面是我在查資料庫的Function

public static DataTable ReadSQLToDT(string pSQL)
{
    string constr = "SQL Connection String";
    DataTable dtSource = new DataTable();
    try
    {
        using (SqlConnection conn = new SqlConnection(constr))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand(pSQL, conn))
            {
                cmd.CommandTimeout = 3;
                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                adapter.Fill(dtSource);
                cmd.Cancel();
                conn.Close();
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    return dtSource;
}

資料量太龐大時
在SqlDataAdapter這邊會出問題
第一個問題是如果我想要將龐大的資料量查完
程式會在60秒左右的時候直接掛掉
直接出現下面的訊息
不管我timeout設定多長都一樣
https://ithelp.ithome.com.tw/upload/images/20230217/20134563j7ob0h3gmd.jpg

第二個問題是如果資料量一樣很龐大的前提下
我想要它時間一到不管有沒有查完就自己timeout跳出來
但這部分設定timeout一樣完全沒作用
一樣會等到差不多60秒的時候跳出上面那個錯誤訊息

想請問是我timeout還是哪邊設定錯呢?

圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
1
實習工程師
iT邦新手 2 級 ‧ 2023-02-17 11:16:59
public static DataTable ReadSQLToDT(string pSQL)
{
    string constr = "SQL Connection String";
    DataTable dtSource = new DataTable();
    try
    {
        using (SqlConnection conn = new SqlConnection(constr))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand(pSQL, conn))
            {
                SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                adapter.SelectCommand.CommandTimeout = 3;
                adapter.Fill(dtSource);
                cmd.Cancel();
                conn.Close();
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    return dtSource;
}

參考文件 : https://social.msdn.microsoft.com/Forums/en-US/74cf7428-ad75-40aa-98f4-4ec7204b9592/how-do-you-change-a-sqldataadapter-commandtimeout?forum=aspgettingstarted

https://stackoverflow.com/questions/30910016/how-to-increase-timeout-of-dataadapter-to-3-min

1
PPTaiwan
iT邦好手 1 級 ‧ 2023-02-17 12:26:35

實習工程師 所提供的

adapter.SelectCommand.CommandTimeout = 3;

其兩段差異不大,但太大量的資料還是會 Timeout 的情形,可以在下達 SQL 透過 SSMS 用戶端統計資料來比較這語法的差異。

但還是建議你太大量的資料,還是以 ROW_NUMBER 來進行分頁查詢,TSQL 裡面做分頁查詢非常的簡單可以詢問 ChatGPT 來提供你分頁的 TSQL 語法

對,其實差異也不太大,還是要看實際資料的資料量去做判斷。

1
JamesDoge
iT邦高手 1 級 ‧ 2023-02-18 14:47:36

以下是一個分批查詢資料的範例,將資料分段填充到 DataTable 中,以避免一次性查詢大量資料的問題:

public static DataTable ReadSQLToDT(string pSQL)
{
    string constr = "SQL 連線字串";
    DataTable dtSource = new DataTable();
    try
    {
        using (SqlConnection conn = new SqlConnection(constr))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand(pSQL, conn))
            {
                cmd.CommandTimeout = 60;
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    // 每次查詢的記錄數
                    int batchSize = 1000;
                    // 當前已經讀取的記錄數
                    int currentCount = 0;
                    // 設置 DataTable 的結構
                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        dtSource.Columns.Add(reader.GetName(i), reader.GetFieldType(i));
                    }

                    // 逐批將資料填充到 DataTable 中
                    while (reader.Read())
                    {
                        DataRow row = dtSource.NewRow();
                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            row[i] = reader.GetValue(i);
                        }
                        dtSource.Rows.Add(row);
                        currentCount++;
                        // 每達到批次大小,就提交到 DataTable 中,並清空 DataRow 集合
                        if (currentCount % batchSize == 0)
                        {
                            dtSource.AcceptChanges();
                            dtSource.Clear();
                        }
                    }

                    // 將剩餘的資料提交到 DataTable 中
                    if (dtSource.Rows.Count > 0)
                    {
                        dtSource.AcceptChanges();
                    }
                }
                cmd.Cancel();
                conn.Close();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        return dtSource;
    }

另外,如果需要處理大量資料,也可以考慮使用 ORM 框架(例如 Entity Framework)處理資料,這樣可以避免手動處理記憶體和資料庫的交互。

我要發表回答

立即登入回答