2008-10-14 2 views
1

Редактировать:
Моя проблема больше не проблема: у меня есть повторные тесты моих исполнений, и у меня есть смертельная глупая ошибка: я забыл x1000, чтобы получить секунды с миллисекунды:/ Жаль за этих ребят.
Для справки:
- Я делаю около 1900 обновлений в секунду с моего компьютера на сервер базы данных в локальной сети.
- 3.200 обновлений в секунду, если программы находятся на одной машине, кроме БД.
- 3.500 обновлений в секунду с моего ПК на сервере DataBase Я не воссоздаю и не открываю новое SQLConnection.
- 5.800 обновлений в секунду с пакетным текстом. Для моих 10.000 строк, если это занимает 5 секунд, это нормально для моих программ. Извините, что беспокоитесь.
C# -SQL: Как выполнить пакет StoredProcedure?

На самом деле, я использую хранимую программу SQL для создания строки в моей базе данных, чтобы избежать SQL-инъекции. В C# у меня есть следующий метод:

public void InsertUser(string userCode) 
{ 
    using (SqlConnection sqlConnection = new SqlConnection(this.connectionString)) 
    { 
     SqlCommand sqlCommand = new SqlCommand("InsertUser", sqlConnection); 
     sqlCommand.CommandType = System.Data.CommandType.StoredProcedure; 
     sqlCommand.Parameters.Add(new SqlParameter("@UserCode", userCode)); 
     sqlConnection.Open(); 
     sqlCommand.ExecuteNonQuery();///0.2 seconds !ERROR HERE! 0.2ms here,NOT 0.2sec!!! 
    } 
} 

Это хорошо, когда у меня есть одна или две строки для вставки. Но если мне нужно создать 1.000 пользователей и 10.000 продуктов и 5000 домашних животных, это не лучшее решение: я потеряю огромное время в netwok транспорте.

Я верю, не проверив, что я могу использовать только ограниченное количество обратных вызовов. Так что я не хочу называть 10.000 раз:

sqlCommand.BeginExecuteNonQuery() 

Другим способом будет создавать текст пакета, но существует риск SQL-Injection (и это некрасиво).

Есть ли объект «SqlCommandList», который управляет этим .Net? Как делать большие записи в базе данных? Какой хороший патерн для этого?

+0

Я бы порекомендовал использовать «sqlCommand.Prepare();» с типом параметра, который должен, по крайней мере, улучшить время выполнения второго запроса. – 2012-05-21 07:22:52

ответ

0

Рассматривали ли вы передачу XML-документа хранимой процедуре, а затем итерацию, чтобы найти данные для вставки?

2

Лично я регулярно планирую делать довольно большие вставки (10 000 строк определенно квалифицируются ...), я мог бы рассмотреть возможность наличия отдельной таблицы для входящих данных и использовать SqlBulkCopy для заполнения этой таблицы. Затем вы просто выполняете одну хранимую процедуру, которая перемещает данные в реальную таблицу.

Другой подход заключается в отправке xml в базу данных и использовании sqlxml для синтаксического анализа (намного проще с SQL2005 и выше), но это добавляет дополнительную работу на сервер db.

0

«это не лучшее решение: я потеряю огромное время в сети транспорта» Можете ли вы жить с потерей?

Если это нечасто, то это имеет значение? Сначала измерьте его, если это проблема, тогда исправьте его, лично, вероятно, я поеду с таблицей Марка Гравеллса для входящих вставок. Другой вариант заключается в том, чтобы асинхронно запускать вставки, а затем вы не дожидаетесь завершения каждого из них до того, как вы начнете следующее.

Мне потребовались годы, но, наконец, я понял, что не должен тратить время на оптимизацию кода, который ему не нужен.

Надеюсь, что это поможет (хотя я и не думаю, что это будет, извините).

9

Это должно работать немного быстрее:

public void InsertUser(IEnumerable<string> userCodes) 
{ 
    using (SqlConnection sqlConnection = new SqlConnection(this.connectionString), 
      SqlCommand sqlCommand = new SqlCommand("InsertUser", sqlConnection)) 
    { 
     sqlCommand.CommandType = System.Data.CommandType.StoredProcedure; 
     SqlParameter param = sqlCommand.Parameters.Add("@UserCode", SqlDbTypes.VarChar); 
     sqlConnection.Open(); 

     foreach(string code in userCodes) 
     { 
      param.Value = code; 
      sqlCommand.ExecuteNonQuery();///0.2 seconds 
     } 
    } 
} 

Это будет только открыть одно подключение и создать только одну команду, даже если вы передаёте 1000 пользователей. Тем не менее, он все равно будет делать каждую вставку отдельно. И, конечно, если userCode не является строкой, вы захотите соответствующим образом изменить его. Вы также можете просмотреть команду SQL BULK INSERT.

2

Если вы действительно были обеспокоены этим, вы можете (как вы сказали) пакетные команды вверх в строках, как так:

var cmd = new SqlCommand(); 
cmd.Connection = sqlConnection; 
for (int i = 0; i < batchSize; i++) { 
    cmd.CommandText += String.Format("EXEC InsertUser @UserCode{0};", i); 
    cmd.Parameters.AddWithValue("@UserCode" + i.ToString(), XXXXX); 
    //... etc ... 
} 

Потому что в этой схеме, вы бы с помощью параметра, вы не У меня больше риск SQL-инъекции, чем при использовании хранимой процедуры. Но я сомневаюсь, действительно ли вы сэкономите значительное время на это. ИМО, вы должны просто держать его простым и делать это так, как вы это делаете сейчас.

+0

Существует много накладных расходов при повторном создании команды и постоянном открытии и закрытии новых соединений. – 2008-10-14 13:12:43

+1

Кроме того, если вы сделаете это так, используйте команду stringbuilder для сборки команды. – 2008-10-14 13:14:09

2

Основываясь на ответе Джоэла, это самое быстрое решение, не использующее SqlBulkCopy или создание больших строк беспорядочного SQL и выполнение. (Я добавил сделку, которая позволит повысить производительность довольно много)

public void InsertUser(IEnumerabler<string> userCodes) 
{ 
    using (SqlConnection sqlConnection = new SqlConnection(this.connectionString)) 
    { 
     sqlConnection.Open(); 
     SqlTransaction transaction = connection.BeginTransaction(); 
     SqlCommand sqlCommand = new SqlCommand("InsertUser", sqlConnection); 
     sqlCommand.Transaction = transaction; 
     sqlCommand.CommandType = System.Data.CommandType.StoredProcedure; 
     SqlParameter param = sqlCommand.Parameters.Add("@UserCode", SqlDbTypes.VarChar); 

     foreach(string code in userCodes) 
     { 
      param.Value = code; 
      sqlCommand.ExecuteNonQuery(); 
     }  
     transaction.Commit(); 
    } 
} 
0

В соответствии с некоторыми из приведенных выше ответов, наиболее заметное увеличение производительности при минимальных усилиях включает 2 изменений в существующий код:

  1. Обертка обновлений в транзакции
  2. Открытие только одного соединения и вызов процедуры несколько раз с различными параметрами.

БОЛЬШИЕ ВСТАВКИ - это вариант, но, вероятно, перебор за то, что вы хотите сделать.

3

Как насчет UpdateBatchSize SQLDataAdaptor?

Наши передний конец ребята используют это, чтобы партия несколько 10000 прок вызывает на куски

Article

MSDN

Наша окружающая среда не позволяет «bulkadmin» права, поэтому мы не можем использовать BULKINSERT/BCP и т.д.

1

Я предполагаю, что это довольно старый вопрос.

С SQL Server 2008 ответ теперь должен использовать параметр значения таблицы. Короче говоря, передайте все ваши переменные в используемом определенном типе (таблице).

В SQL теперь вы можете обрабатывать все записи как отдельные элементы ... На самом деле используйте логику набора и получите реальную производительность.

Смежные вопросы