Как размер партии влияет на объемную вставку? - PullRequest
3 голосов
/ 29 декабря 2011

Я выполняю массовую вставку в базу данных syabse, группируя запрос на вставку и отправляя его в базу данных в пакетном режиме, где размер пакета настраивается, код выглядит примерно так

public static void InsertModelValueInBulk(DataSet modelValueData, int clsaId)
    {
        int batchSize = Convert.ToInt32(ConfigurationManager.AppSettings["BatchSize"].ToString());            
        IList<string> queryBuffer = new List<string>();    
        using (var connection = GetAseConnection())
        {
            connection.Open();
            var tran = connection.BeginTransaction();
            try
            {                  
                for (int i = 0; i < modelValueData.Tables[0].Rows.Count; i++)
                {

                    var insertItem = string.Format(@"select '{0}',{1},{2},{3},'{4}','{5}','{6}',{7}", row["ModelValueID"], Convert.ToInt32(row["StockModelID"]), Convert.ToInt32(row["ModelItemID"]),
                                                                      fyeStr, row["Period"], value, row["UpdatedUser"], clsaId);
                    queryBuffer.Add(insertItem);
                    if (queryBuffer.Count % (batchSize) == 0 && queryBuffer.Count > 0)
                    {
                        var finalQuery = @"INSERT INTO InsertTable (ModelValueID, StockModelID, ModelItemID, FYE, Period, Value, UpdatedUser,id) 
         " + String.Join(" union ", queryBuffer.ToArray<string>());                         

                        using (var cmd = new AseCommand(finalQuery, connection, tran))
                        {                                    
                                cmd.ExecuteNonQuery();                              
                        }
                        queryBuffer.Clear();
                    }                      
                }                   
                tran.Commit();
            }
            catch
            {
                tran.Rollback();
                throw;
            }
            finally
            {
                tran.Dispose();
            }
        }
    }

, используя эту производительность, наблюдаемую дляразмер партии в зависимости от времени, необходимого для вставки 20000, образует кривую J, данные выборки примерно такие же, как

размер партии 10 => Операция завершается через 30 секунд, когда размер партии составляет 50 => 20 секунд, 100 => 10 секунд, 200 => 20 с, 500 30 с, 1000 => 1 мин.

Хотелось бы понять, что является причиной этой J-кривой.Это связано с памятью сервера приложений, настройкой сервера базы данных или чем-то еще?Что делает 100 оптимальным и можно ли это изменить дальше?

Ответы [ 2 ]

3 голосов
/ 29 декабря 2011

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

Так что большие партии хороши, в точку. Поскольку это транзакция, данные не фиксируются, пока текущий пакет не будет завершен. Это означает запись в файл журнала. Реально большие партии приведут к увеличению объема журнала, что приводит к интенсивному вводу-выводу, а также к увеличению конкуренции за использование большего количества журналов.

Что-то в этом роде.

редактировать: две другие вещи 1) Используйте параметризованные входы 2) Если вы не делаете # 1, «союз» вызывает отличное. Используйте "union all"

1 голос
/ 29 декабря 2011

Я вижу довольно много проблем с вашим существующим кодом ... например .. в вашем коммите. Я бы не предполагал, что коммиты всегда будут успешными ..

  1. Я бы обернул весь код, который мог бы потерпеть неудачу или взорваться вокруг попытки перехвата Commits, Rollbacks cmd.Execute

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

  3. Я бы назвал свои транзакции лично ... но это зависит от вас

  4. может ли эта строка изменяться при каждом вызове метода ..

    int batchSize = Convert.ToInt32 (ConfigurationManager.AppSettings ["BatchSize"]. ToString ());
    в противном случае я бы сделал статический вызов и не вызывал бы его каждый раз, когда вы входите в метод

  5. попытаться реорганизовать ваш код .. это выглядит немного запутанно, чтобы следовать ..
...