對於海量數據的插入和更新
ADO
NET確實不如JDBC做到好
JDBC有統一的模型來進行批操作
使用起來
非常方便
PreparedStatement ps = conn
prepareStatement(
insert or update arg
args
…
)
然後你就可以
for(int i=
;i<
;i++){
ps
setXXX(realArg)
……
ps
addBatch()
if(i%
==
){ //假設五百條提交一次
ps
executeBatch()
//clear Parame Batch
}
}
ps
executeBatch()
這樣的操作不僅帶來極度大的性能
而且非常方便
按說
ADO
NET中
要實現這樣的功能
應該直接在Command接口中
或DataAdapter接口中提供Addbat和CommitBat的API
但ADO
NET的卻並沒有這樣簡單地實現
而是要求開發者通過
復雜的變通方法
對於大量的插入操作
可以利用一個空的DataTable加入要插入的行
達到一定數量提交後清空該表就行了
實現起來並不算復雜
DateTime begin = DateTime
Now;
string connectionString = ……
using(SqlConnection conn = new SqlConnection(connectionString))…{
conn
Open()
SqlDataAdapter sd = new SqlDataAdapter()
sd
SelectCommand = new SqlCommand(
select devid
data_time
data_value from CurrentTest
conn)
sd
InsertCommand = new SqlCommand(
insert into CurrentTest (devid
data_time
data_value)
+
values (@devid
@data_time
@data_value)
conn)
sd
InsertCommand
Parameters
Add(
@devid
SqlDbType
Char
devid
)
sd
InsertCommand
Parameters
Add(
@data_time
SqlDbType
Char
data_time
)
sd
InsertCommand
Parameters
Add(
@data_value
SqlDbType
Int
data_value
)
sd
InsertCommand
UpdatedRowSource = UpdateRowSource
None;
sd
UpdateBatchSize =
;
DataSet dataset = new DataSet()
sd
Fill(dataset)
Random r = new Random(
)
for (int i =
; i <
; i++) …{
object[] row = …{
DEVID
+i
DateTime
Now
ToString(
yyyy
MM
dd HH:mm:ss
)
r
Next(
) };
dataset
Tables[
]
Rows
Add(row)
if (i %
==
) …{
sd
Update(dataset
Tables[
])
dataset
Tables[
]
Clear()
}
}
sd
Update(dataset
Tables[
])
dataset
Tables[
]
Clear()
sd
Dispose()
dataset
Dispose()
conn
Close()
}
TimeSpan ts = DateTime
Now
begin;
MessageBox
Show(
ts =
+ ts
TotalMilliseconds)
對於這個測試我插入
萬條數據用時
秒
性能還算可圈可點
但是對於批量更新
搜遍全球的例子
都是把記錄Fill到DataSet中然後牧舉rows
來更新
就我這個小數據量的測試而言
把
萬條數據Fill到DataSet中已經不能工作
如果是百萬
千萬如何操作?難道一定先把要批操作的記錄
先獲取到DataSet中?也就是我要更新哪些記錄就要選查詢這些記錄?
於是我仍然利用一個空的DataTable來加入要更新的記錄
sd
SelectCommand = new SqlCommand(
select devid
data_time
data_value from CurrentTest where
=
conn)
//
=
的條件保證取一個空表
sd
UpdateCommand = new SqlCommand(
update CurrentTest set data_time = @data_time
data_value = @data_value where devid = @devid
conn)
sd
UpdateCommand
Parameters
Add(
@data_time
SqlDbType
Char
data_time
)
sd
UpdateCommand
Parameters
Add(
@data_value
SqlDbType
Int
data_value
)
sd
UpdateCommand
Parameters
Add(
@devid
SqlDbType
Char
devid
)
sd
UpdateCommand
UpdatedRowSource = UpdateRowSource
None;
sd
UpdateBatchSize =
;
for(int i=
;i<
;i++){
……
dataset
Tables[
]
Rows
Add(row)
}
sd
Update(dataset
Tables[
])
先更新
條試試
如果成功再循環更新所有記錄
但提示插入操作需要InsertCommand
因為一個空表然後Add Row操作
這時RowState是Added
如果這時Update到數據庫
執行的就是插入操作而無法更新
改成
for(int i=
;i<
;i++){
……
row = {填入初始化的值};
dataset
Tables[
]
Rows
Add(row)
}
dataset
AcceptChanges()
for(int i=
;i<
;i++){
……
dataset
Tables[
]
Rows[i][x] =
xxxxxxx
;
……
}
sd
Update(dataset
Tables[
])
先在DataTable中插入數據
然後用AcceptChanges()
修改RowState為UnChanged
再修改表中數據希望改變 UnChanged狀態
即將DataTable從Current狀態改為Original
然後再對DataTable的Row進行更新
就能使
Update成功
但這樣做確實不方便
調整思路
先從數據庫中取
條(批更新的Size大小)
直接得到一個Original的DataTable
sd
SelectCommand = new SqlCommand(
select top
devid
data_time
data_value from CurrentTest
conn)
DataSet dataset = new DataSet()
sd
Fill(dataset)
用這
個空間來放要更新的其它數據看看
for (int i =
; i <
; i++)
{
dataset
Tables[
]
Rows[i]
BeginEdit()
dataset
Tables[
]
Rows[i][
data_time
] =
:
:
;
dataset
Tables[
]
Rows[i][
data_value
] =
;
dataset
Tables[
]
Rows[i][
devid
] =
DEVID
+(i+
)
//更新DEVID
到DEVID
的記錄
dataset
Tables[
]
Rows[i]
EndEdit()
}
sd
Update(dataset
Tables[
])
OK
成功
哈哈
把要更新的數據不斷往這個空間填
填滿就提交
這樣更新
條數據只要幾個循環就行了
DateTime begin = DateTime
Now;
string connectionString =
;
using(SqlConnection conn = new SqlConnection(connectionString))…{
conn
Open()
SqlDataAdapter sd = new SqlDataAdapter()
sd
SelectCommand = new SqlCommand(
select top
devid
data_time
data_value from CurrentTest
conn)
DataSet dataset = new DataSet()
sd
Fill(dataset)
Random r = new Random(
)
sd
UpdateCommand = new SqlCommand(
update CurrentTest
+
set data_time = @data_time
data_value = @data_value where devid = @devid
conn)
sd
UpdateCommand
Parameters
Add(
@data_time
SqlDbType
Char
data_time
)
sd
UpdateCommand
Parameters
Add(
@data_value
SqlDbType
Int
data_value
)
sd
UpdateCommand
Parameters
Add(
@devid
SqlDbType
Char
devid
)
sd
UpdateCommand
UpdatedRowSource = UpdateRowSource
None;
sd
UpdateBatchSize =
;
for (int count =
; count <
;)
…{
for (int i =
; i <
; i++
count++)
…{
dataset
Tables[
]
Rows[i]
BeginEdit()
dataset
Tables[
]
Rows[i][
data_time
] =
:
:
;
dataset
Tables[
]
Rows[i][
data_value
] =
;
dataset
Tables[
]
Rows[i][
devid
] =
DEVID
+count;
dataset
Tables[
]
Rows[i]
EndEdit()
}
sd
Update(dataset
Tables[
])
}
dataset
Tables[
]
Clear()
sd
Dispose()
dataset
Dispose()
conn
Close()
}
TimeSpan ts = DateTime
Now
begin;
MessageBox
Show(
ts =
+ ts
TotalMilliseconds)
注意上面的更新操作是指在一個十萬
百萬
千萬條記錄中我要不斷更新其中的記錄
這些要更新的記錄並不是從頭
到尾這樣的順序
只是不斷地根據條件更新任何記錄
我不可能把成百上千萬記錄先Fill到ds中然後在ds中Select到
這條記錄然後更新
所以每
次更新操作填入一次DataTable中提交
就實現了JDBC的addBat和executeBat操作
這個操作更新
萬條用了
秒
還算勉強吧
From:http://tw.wingwit.com/Article/program/net/201311/11281.html