.Net程序中可以通過ODP調(diào)用特性,對Oracle數(shù)據(jù)庫進(jìn)行操作,今天來講一下數(shù)據(jù)批量插入的功能,所用技術(shù)不高不深,相信很多朋友都接觸過。
(1)普通肉墊式
什么叫批量插入呢,就是一次性插入一批數(shù)據(jù),我們可以把這批數(shù)據(jù)理解為一個大的數(shù)組,而這些全部只通過一個SQL來實現(xiàn),而在傳統(tǒng)方式下,需要調(diào)用很多次的SQL才可以完成,這就是著名的“數(shù)組綁定”的功能。我們先來看一下傳統(tǒng)方式下,插入多行記錄的操作方式:
//設(shè)置一個數(shù)據(jù)庫的連接串,
string connectStr = "User Id=scott;Password=tiger;Data Source=";
OracleConnection conn = new OracleConnection(connectStr);
OracleCommand command = new OracleCommand();
command.Connection = conn;
conn.Open();
Stopwatch sw = new Stopwatch();
sw.Start();
//通過循環(huán)寫入大量的數(shù)據(jù),這種方法顯然是肉墊
for (int i = 0; i < recc; i++)
{
string sql = "insert into dept values(" + i.ToString()
+ "," + i.ToString() + "," + i.ToString() + ")";
command.CommandText = sql;
command.ExecuteNonQuery();
}
sw.Stop();
System.Diagnostics.Debug.WriteLine("普通插入:" + recc.ToString()
+ "所占時間:" + sw.ElapsedMilliseconds.ToString());
我們先準(zhǔn)備好程序,但是先不做時間的測定,因為在后面我們會用多次循環(huán)的方式來計算所占用的時間。
(2)使用ODP特性
看上面的程序,大家都很熟悉,因為它沒有用到任何ODP的特性,而緊接著我們就要來介紹一個神奇的程序了,我們看一下代碼,為了更直觀,我把所有的注釋及說明直接寫在代碼里:
//設(shè)置一個數(shù)據(jù)庫的連接串
string connectStr = "User Id=scott;Password=tiger;Data Source=";
OracleConnection conn = new OracleConnection(connectStr);
OracleCommand command = new OracleCommand();
command.Connection = conn;
//到此為止,還都是我們熟悉的代碼,下面就要開始嘍
//這個參數(shù)需要指定每次批插入的記錄數(shù)
command.ArrayBindCount = recc;
//在這個命令行中,用到了參數(shù),參數(shù)我們很熟悉,但是這個參數(shù)在傳值的時候
//用到的是數(shù)組,而不是單個的值,這就是它獨特的地方
command.CommandText = "insert into dept values(:deptno, :deptname, :loc)";
conn.Open();
//下面定義幾個數(shù)組,分別表示三個字段,數(shù)組的長度由參數(shù)直接給出
int[] deptNo = new int[recc];
string[] dname = new string[recc];
string[] loc = new string[recc];
// 為了傳遞參數(shù),不可避免的要使用參數(shù),下面會連續(xù)定義三個
// 從名稱可以直接看出每個參數(shù)的含義,不在每個解釋了
OracleParameter deptNoParam = new OracleParameter("deptno",
OracleDbType.Int32);
deptNoParam.Direction = ParameterDirection.Input;
deptNoParam.Value = deptNo;
command.Parameters.Add(deptNoParam);
OracleParameter deptNameParam = new OracleParameter("deptname",
OracleDbType.Varchar2);
deptNameParam.Direction = ParameterDirection.Input;
deptNameParam.Value = dname;
command.Parameters.Add(deptNameParam);
OracleParameter deptLocParam = new OracleParameter("loc",
OracleDbType.Varchar2);
deptLocParam.Direction = ParameterDirection.Input;
deptLocParam.Value = loc;
command.Parameters.Add(deptLocParam);
Stopwatch sw = new Stopwatch();
sw.Start();
//在下面的循環(huán)中,先把數(shù)組定義好,而不是像上面那樣直接生成SQL
for (int i = 0; i < recc; i++)
{
deptNo[i] = i;
dname[i] = i.ToString();
loc[i] = i.ToString();
}
//這個調(diào)用將把參數(shù)數(shù)組傳進(jìn)SQL,同時寫入數(shù)據(jù)庫
command.ExecuteNonQuery();
sw.Stop();
System.Diagnostics.Debug.WriteLine("批量插入:" + recc.ToString()
+ "所占時間:" +sw.ElapsedMilliseconds.ToString());
以上代碼略顯冗長,但是加上注釋后基本也就表達(dá)清楚了。
當(dāng)數(shù)據(jù)量達(dá)到100萬級別時,所用時間依然令人滿意,最快一次達(dá)到890毫秒,一般為1秒左右。
好了,到目前為止,兩種方式的插入操作程序已經(jīng)完成,就剩下對比了。我在主函數(shù)處寫了一個小函數(shù),循環(huán)多次對兩個方法進(jìn)行調(diào)用,并且同時記錄下時間,對比函數(shù)如下:
for (int i = 1; i <= 50; i++)
{
Truncate();
OrdinaryInsert(i * 1000);
Truncate();
BatchInsert(i * 1000);
}
經(jīng)過試驗,得出一組數(shù)據(jù),可以看出兩種方式在效率方面驚人的差距(占用時間的單位為毫秒),部分?jǐn)?shù)據(jù)如下:
記錄數(shù) |
標(biāo)準(zhǔn) |
批處理 |
1000 |
1545 |
29 |
2000 |
3514 |
20 |
3000 |
3749 |
113 |
4000 |
5737 |
40 |
5000 |
6820 |
52 |
6000 |
9469 |
72 |
7000 |
10226 |
69 |
8000 |
15280 |
123 |
9000 |
11475 |
83 |
10000 |
14536 |
121 |
11000 |
15705 |
130 |
12000 |
16548 |
145 |
13000 |
18765 |
125 |
14000 |
20393 |
116 |
15000 |
22181 |
159 |
因為篇幅原因,不再粘貼全部的數(shù)據(jù),但是我們可以看一下由此數(shù)據(jù)生成的散點圖:
其中有些數(shù)據(jù)有些跳躍,可能和數(shù)據(jù)庫本身有關(guān)系,但是大部分?jǐn)?shù)據(jù)已經(jīng)能說明問題了??戳诉@些數(shù)據(jù)后,是不是有些心動了?
源程序放了一段時間直接拷貝貼過來了,可能需要調(diào)試一下才能跑通,不過不是本質(zhì)性問題,對了如果要測試別忘記安裝Oracle訪問組件。
新聞熱點
疑難解答
圖片精選