DataTable新增資料之效率問題

07 May 2010 — Written by Sky Chang
#ASP.NET

最近讀到一篇不錯的文章,

內容是在說使用DataTable新增資料,怎樣才會快

[原文

](http://marlon.blog.ithome.com.tw/post/894/70698)此外,原作者還有很多不錯的文章,大家可以去看看。

我引用了這篇原文,順便加上些自己的看法與註解。

DataTable 新增資料,這麼簡單的問題有誰不會?但是您用對方法了嗎?如果是新增一筆資料給使用者輸入,用什麼方法沒有太大的差別,但如果是用程式碼大量新增資料,不同的方法時間可以差上數倍,欄位越多越明顯,廢話不多說,直接看不同的寫法測試數據

測試 20 個字串欄位及 20 個整數欄位, 無 Constraints, 新增 10000 筆資料,

每種方法測試10次, 去除最大及最小值後分列列出其餘8次中 (最小值, 平均值, 最大值), 單位 Milliseconds

( 有興趣者可測試有 Constraints 時方法一與方法二的差異 )

方法一 ( 405.6, 416.0, 426.4 )

DataRow row;
for (int rowIndex = 1; rowIndex <= RowCount; rowIndex++)
{
  row = table.NewRow();
  for (int i = 1; i <= ColCount; i++)
  {
    row["ColString" + i.ToString()] = string.Concat(rowIndex.ToString(), ".", i.ToString());
    row["ColInt" + i.ToString()] = rowIndex * 1000 + i;
  }
table.Rows.Add(row);
}

SanC : 這是我們最常用的方法,在撰寫時,算是最直覺的寫法。

方法二 ( 390.0, 395.9, 405.6 )

DataRow row;
table.BeginLoadData();
for (int rowIndex = 1; rowIndex <= RowCount; rowIndex++)
{
  row = table.NewRow();
  for (int i = 1; i <= ColCount; i++)
  {
    row["ColString" + i.ToString()] = string.Concat(rowIndex.ToString(), ".", i.ToString());
    row["ColInt" + i.ToString()] = rowIndex * 1000 + i;
  }
table.Rows.Add(row);
}
table.EndLoadData();

SanC:

這個方法修正了方法一的地方,

最顯著的是將使用table.BeginLoadData()和table.EndloadData()放在最外圈,

我的猜測,再沒寫這兩個Function時,當執行10000次時,也同時呼叫了10000次的這兩個function

所以,速度也慢了。

方法三 ( 234.0, 245.1, 254.8 )

int[] strColIndex = new int[ColCount];
int[] intColIndex = new int[ColCount];
for (int i = 1; i <= ColCount; i++)
{
  strColIndex[i - 1] = table.Columns["ColString" + i.ToString()].Ordinal;
  intColIndex[i - 1] = table.Columns["ColInt" + i.ToString()].Ordinal;
}

DataRow row;
table.BeginLoadData();
for (int rowIndex = 1; rowIndex <= RowCount; rowIndex++)
{
  row = table.NewRow();
  for (int i = 1; i <= ColCount; i++)
  {
    row[strColIndex[i - 1]] = string.Concat(rowIndex.ToString(), ".", i.ToString());
    row[intColIndex[i - 1]] = rowIndex * 1000 + i;
  }
table.Rows.Add(row);
}
table.EndLoadData();

SanC:

這裡使用陣列strColIndex和intColIndex來存欄位名稱的編號

( 例如: 欄位名稱ColSting1的編號為1 ColString2的編號為2 )

此陣列就是來存取此值,

然後在新增資料的時候,使用的不是用字串當索引

( 字串當索引 row["ColString1"] )

而是使用數字( 編號 )當索引,在不經過查詢(轉換)的過程,

使得速度更快了。

方法四 ( 119.6, 127.4, 135.2 ) - 較佳寫法, 使用 object[] 新增資料

int[] strColIndex = new int[ColCount];
int[] intColIndex = new int[ColCount];
for (int i = 1; i <= ColCount; i++)
{
  strColIndex[i-1] = table.Columns["ColString" + i.ToString()].Ordinal;
  intColIndex[i-1] = table.Columns["ColInt" + i.ToString()].Ordinal;
}

object[] itemArray;
table.BeginLoadData();
for (int rowIndex = 1; rowIndex <= RowCount; rowIndex++)
{
  itemArray = new object[table.Columns.Count];
  for (int i = 1; i <= 10; i++)
  {
    itemArray[strColIndex[i-1]] = string.Concat(rowIndex.ToString(), ".", i.ToString());
    itemArray[intColIndex[i-1]] = rowIndex * 1000 + i;
  }
table.Rows.Add(itemArray);
}
table.EndLoadData();

SanC:

又更加的改進,這裡使用object來做處理,而非使用DataRow來新增,

先建立一個名為 itemArray的object陣列

然後再將每個資料塞到陣列裡的每個物件裡,

然後再用table.Rows.Add(itemArray)來新增所有資料

這是最快的處理方法,至於為何,只能猜測因為object型別最單純!?

或是中間不需要經過轉換的過程。

Sky & Study4.TW