Для вставки и обновления больших данных ADO.NET действительно не так хорош, как JDBC. JDBC имеет унифицированную модель пакетных операций. Очень удобно использовать:
ReadedStatement ps = conn.prepareStatement("вставьте или обновите arg1,args2....");
тогда ты сможешь
for(int i=0;i<1000000000000000;i++){
ps.setXXX(realArg);
.....
ps.addBatch();
if(i%500==0){ //Предположим, пятьсот элементов отправлены один раз
пс.executeBatch();
//очистить пакет параметров
}
}
пс.executeBatch();
Такая операция не только обеспечивает чрезвычайно высокую производительность, но и очень удобна. Обычно в ADO.NET для реализации такой функции API-интерфейсы Addbat и CommitBat должны быть предоставлены непосредственно в интерфейсе Command или интерфейсе DataAdapter, а не ADO. NET. Но это реализуется не так просто, а требует от разработчиков сложных обходных путей.
Для большого количества операций вставки вы можете использовать пустой DataTable, чтобы добавить вставляемые строки, а затем очистить таблицу после определенного количества отправок.
Это не слишком сложно реализовать:
DateTime начало = DateTime.Now;
строка ConnectionString = ...;
using (SqlConnection conn = новый SqlConnection (connectionString))... {
конн.Открыть();
SqlDataAdapter sd = новый SqlDataAdapter();
sd.SelectCommand = new SqlCommand("выберите devid,data_time,data_value из CurrentTest", conn);
sd.InsertCommand = new SqlCommand("вставить в CurrentTest (devid,data_time,data_value)"
+ "значения (@devid,@data_time,@data_value);", conn);
sd.InsertCommand.Parameters.Add("@devid", SqlDbType.Char, 18, "devid");
sd.InsertCommand.Parameters.Add("@data_time", SqlDbType.Char, 19, "data_time");
sd.InsertCommand.Parameters.Add("@data_value", SqlDbType.Int, 8, "data_value");
sd.InsertCommand.UpdatedRowSource = UpdateRowSource.None;
sd.UpdateBatchSize = 0;
Набор данных DataSet = новый DataSet();
sd.Fill (набор данных);
Случайный r = новый случайный (1000);
for (int i = 0; i < 100000; i++) ...{
object[] row = ...{"DEVID"+i,DateTime.Now.ToString("гггг-ММ-дд ЧЧ:мм:сс"),r.Next(1,1000) };
dataset.Tables[0].Rows.Add(строка);
если (я % 300 == 0) ...{
sd.Update(dataset.Tables[0]);
набор данных.Таблицы[0].Очистить();
}
}
sd.Update(dataset.Tables[0]);
набор данных.Таблицы[0].Очистить();
сд.Dispose();
набор данных.Dispose();
конн.Закрыть();
}
TimeSpan ts = DateTime.Now — начать;
MessageBox.Show("ts = " + ts.TotalMilliсекунды);
В этом тесте мне потребовалось 28 секунд, чтобы вставить 100 000 фрагментов данных. Производительность весьма впечатляет, но для пакетных обновлений и примеров поиска по всему миру записи заполняются в DataSet, а затем извлекаются строки.
Для обновления, что касается моего теста с небольшим объемом данных, заполнение 100 000 фрагментов данных в DataSet больше не работает. Если их миллионы, как с этим работать? Нужно ли сначала получить записи? Другими словами, какие записи, которые я хочу обновить, должны быть выбраны для запроса этих записей?
Поэтому я по-прежнему использую пустой DataTable для добавления обновляемых записей:
sd.SelectCommand = new SqlCommand("выберите devid,data_time,data_value из CurrentTest, где 1=0", conn);
//Условие 1=0 гарантирует пустую таблицу.
sd.UpdateCommand = new SqlCommand("обновить набор CurrentTest data_time = @data_time,data_value = @data_value, где devid = @devid", conn);
sd.UpdateCommand.Parameters.Add("@data_time", SqlDbType.Char, 19, "data_time");
sd.UpdateCommand.Parameters.Add("@data_value", SqlDbType.Int, 4, "data_value");
sd.UpdateCommand.Parameters.Add("@devid", SqlDbType.Char, 20, "devid");
sd.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;
sd.UpdateBatchSize = 0;
for(int i=0;i<300;i++){
............................
dataset.Tables[0].Rows.Add(строка);
}
sd.Update(dataset.Tables[0]);
Попробуйте сначала обновить 300 записей. Если это удастся, все записи будут обновлены в цикле, но появится сообщение о том, что для операции вставки требуется команда InsertCommand, поскольку это пустая таблица, а затем операция добавления строки. В это время добавляется RowState.
Если в это время в базу данных отправляется обновление, операция вставки выполняется и не может быть обновлена. Измените на:
for(int i=0;i<300;i++){
............................
row = {заполните инициализированное значение};
dataset.Tables[0].Rows.Add(строка);
}
набор данных.ПринятьИзменения();
for(int i=0;i<300;i++){
............................
dataset.Tables[0].Rows[i][x] = "xxxxxxx";
............................
}
sd.Update(dataset.Tables[0]);
Сначала вставьте данные в DataTable, затем используйте AcceptChanges(), чтобы изменить состояние RowState на UnChanged, а затем измените данные в таблице, чтобы изменить состояние UnChanged.
Измените DataTable с текущего состояния на исходное, а затем обновите строку DataTable, вы можете использовать
Обновление прошло успешно. Но делать это действительно неудобно.
Скорректируйте идею, сначала возьмите 200 записей из базы данных (размер пакетного обновления) и сразу получите Original DataTable.
sd.SelectCommand = new SqlCommand("выбрать первые 200 разделов, data_time, data_value из CurrentTest", conn);
Набор данных DataSet = новый DataSet();
sd.Fill (набор данных);
Используйте эти 200 мест для размещения других данных, подлежащих обновлению, и посмотрите:
для (int я = 0; я <100; я++)
{
dataset.Tables[0].Rows[i].BeginEdit();
dataset.Tables[0].Rows[i]["data_time"] = "2222-22-22 22:22:22";
dataset.Tables[0].Rows[i]["data_value"] = 100;
dataset.Tables[0].Rows[i]["devid"] = "DEVID"+(i+10000);//Обновляем записи с DEVID10000 на DEVID10200
dataset.Tables[0].Rows[i].EndEdit();
}
sd.Update(dataset.Tables[0]);
Хорошо, успех, ха-ха. Продолжайте заполнять обновляемые данные в этом пространстве и отправлять их, когда они заполнятся. Таким образом, для обновления 100 000 фрагментов данных потребуется всего несколько циклов.
DateTime начало = DateTime.Now;
строка ConnectionString = "";
using (SqlConnection conn = новый SqlConnection (connectionString))... {
конн.Открыть();
SqlDataAdapter sd = новый SqlDataAdapter();
sd.SelectCommand = new SqlCommand("выбрать первые 200 разделов, data_time, data_value из CurrentTest", conn);
Набор данных DataSet = новый DataSet();
sd.Fill (набор данных);
Случайный r = новый случайный (1000);
sd.UpdateCommand = new SqlCommand("обновить CurrentTest"
+ " set data_time = @data_time,data_value = @data_value где devid = @devid", conn);
sd.UpdateCommand.Parameters.Add("@data_time", SqlDbType.Char, 19, "data_time");
sd.UpdateCommand.Parameters.Add("@data_value", SqlDbType.Int, 4, "data_value");
sd.UpdateCommand.Parameters.Add("@devid", SqlDbType.Char, 20, "devid");
sd.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;
sd.UpdateBatchSize = 0;
for (int count = 0; count < 100000;)
...{
for (int i = 0; i < 200; i++,count++)
...{
dataset.Tables[0].Rows[i].BeginEdit();
dataset.Tables[0].Rows[i]["data_time"] = "2222-22-22 22:22:22";
dataset.Tables[0].Rows[i]["data_value"] = 100;
dataset.Tables[0].Rows[i]["devid"] = "DEVID"+count;
dataset.Tables[0].Rows[i].EndEdit();
}
sd.Update(dataset.Tables[0]);
}
набор данных.Таблицы[0].Очистить();
сд.Dispose();
набор данных.Dispose
http://www.cnblogs.com/Seabiscuit/archive/2010/05/25/1743341.html