У меня есть Handheld-устройство, которое подключается к базе данных Sql Server, считывает данные сервера Sql и получает его в базе данных SQL Compact, расположенной на устройстве. Это мой код:
public void InsertData() // Function insert data into SQL commapct database
{
dt = new DataTable();
dt = SqlServer_GetData_dt("Select id_price, price, id_item from prices", SqlCeConnection); // get data form sql server
if (dt.Rows.Count > 0)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
string sql = "";
sql = "insert into prices" +
" ( id_prices, price,id_item) values('"
+ dt.Rows[i]["id_price"].ToString().Trim() + "', '"
+ dt.Rows[i]["price"].ToString().Trim() + "', '"
+ dt.Rows[i]["id_item"].ToString().Trim() + "')";
obj.SqlCE_WriteData_bit(sql, connection.ConnectionString);//insert into sql compact
}
}
}
public DataTable SqlServer_GetData_dt(string query, string conn)
{
try
{
DataTable dt = new DataTable();
string SqlCeConnection = conn;
SqlConnection sqlConnection = new SqlConnection(SqlCeConnection);
sqlConnection.Open();
{
SqlDataReader darSQLServer;
SqlCommand cmdCESQLServer = new SqlCommand();
cmdCESQLServer.Connection = sqlConnection;
cmdCESQLServer.CommandType = CommandType.Text;
cmdCESQLServer.CommandText = query;
darSQLServer = cmdCESQLServer.ExecuteReader();
dt.Load(darSQLServer);
sqlConnection.Close();
}
return dt;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
DataTable dt = new DataTable();
return dt;
}
}
public object SqlCE_WriteData_bit(string query, string conn)
{
try
{
string SqlCeConnection = conn;
SqlCeConnection sqlConnection = new SqlCeConnection(SqlCeConnection);
if (sqlConnection.State == ConnectionState.Closed)
{
sqlConnection.Open();
}
SqlCeCommand cmdCESQLServer = new SqlCeCommand();
cmdCESQLServer.Connection = sqlConnection;
cmdCESQLServer.CommandType = CommandType.Text;
cmdCESQLServer.CommandText = query;
object i = cmdCESQLServer.ExecuteScalar();
sqlConnection.Close();
return i;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return 0;
}
}
Все это прекрасно работает, но проблема в том, что все это работает очень медленно. У меня 20 000 строк, которые необходимо вставить в базу данных SQL compact.
Есть ли способ ускорить вставку?
Благодарю.
Помимо очевидного плохого использования соединения для каждого вызова, вы можете значительно улучшить ситуацию, также полностью устранив процессор запросов. Это означает, что вы не используете SQL. Вместо этого откройте таблицу назначения TableDirect
и SqlCeResultset
. Итерация по исходным данным (DataTable - плохая идея, но это совершенно другая вещь) и используйте серию CreateRecord
, SetValues
и Insert
.
Хороший пример можно найти здесь (хотя, опять же, я бы использовал SetValues
для установки всей строки, а не каждого отдельного поля).
Поместите все данные в DataTable
а затем используйте SqlCeDataAdapter
для сохранения всех данных с помощью одного вызова Update
. Возможно, вам придется играть с UpdateBatchSize
чтобы получить максимальную производительность.
Глядя более внимательно, я вижу, что у вас уже есть DataTable
. Поэтому циклы через него сами по себе смехотворны. Просто отметьте, что, как и у вас, RowState
каждого DataRow
будет Unchanged
, поэтому они не будут вставлены. Я думаю, что вы можете вызвать DataTable.Load
таким образом, чтобы все значения RowState
оставались как Added
но если нет, то вместо этого используйте SqlDataAdapter
, установите значение AcceptChangesDuringFill
false
и вызовите Fill
.
Повторно используйте свое соединение и не создавайте новое соединение для каждого оператора INSERT
.
Вместо того, чтобы передавать строку соединения в ваш метод SqlCE_WriteData_bit
, создайте соединение один раз в методе InsertData
и передайте объект соединения в SqlCE_WriteData_bit
.
Есть ли способ ускорить вставку?
Да, но это, вероятно, не будет "приемлемо достаточно быстро", когда мы говорим о вставке 20 тыс. Строк.
Проблема, которую я вижу, заключается в том, что вы открываете соединение для каждой строки, которую вы SqlServer_GetData_dt
из SqlServer_GetData_dt
, то есть вы открываете соединение для вставки данных в 20 000 раз... открытие соединения - дорогостоящая транзакция. Вы должны построить весь запрос, используя объект StringBuilder
а затем выполнить все инструкции insert в одной партии.
Это принесет некоторую выгоду в производительности, но не ожидайте, что она решит вашу проблему. Вставка строк 20k все равно займет некоторое время, особенно если индексы необходимо перестроить. Мое предложение состоит в том, что вы должны тщательно анализировать свои требования и быть немного умнее о том, как вы к нему подходите. Возможные варианты:
insert
в фоновом режиме и получите доступ к данным только при завершении предварительного заполнения