Модераторы: gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Вставка большого обьема данных в БД Access, порядка 30-40 тысяч строк 
V
    Опции темы
thomas
Дата 25.11.2007, 13:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент... почти
***


Профиль
Группа: Завсегдатай
Сообщений: 1385
Регистрация: 3.10.2006
Где: " Сказочное королевство"

Репутация: 35
Всего: 65



Приветствую всех.
Ситуация. Написал программу, работающую с БД в Access. Программа создает в БД таблицы и заполняет их данными (список почтовых адресов).
Т.е. в БД создается необходимая таблица, динамически указываются наименования и типы полей(на момент создания таблица пуста), далее в ДатаСет создается идентичная таблица и заполняется данными с генерацией первичного ключа(каждая строка имеет уникальный ID). Создается  30-40 тысяч строк. Сейчас реализовал вставку данных перебором строк таблицы ДатаСета через INSERT команду. На машине с CPU 1.4Гг и 1,25 гектара оперативной памяти эта операция занимает порядка 40 минут. 

Вопрос : Как ускорить вставку данных?


--------------------
Крепко жму горло, искренне ваш Thomas. (С)vingrad
Некоторые сорта флоры буквально за одно мгновение превращают нас в фауну!
Проблемы негров шерифа не волнуют.
PM MAIL   Вверх
tol05
Дата 25.11.2007, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 11
Всего: 170



thomas, ты же на форуме не первый день!.. 

"Я делаю таблицу и вставляю данные через INSERT. Почему так долго"

Разве может тебе кто-нибудь ответить? Вряд ли тебя устроит ответ типа такого:
"Нет, этого просто не может быть!!! MS SQL вместе с ADO.NET уже давно бы в трубу вылетели с такой производительностью. По миру пошли бы, даже мы с тобой их бы не купили..."   

smile  (без обид)

Ну давай код показывай что-ли...

Это сообщение отредактировал(а) tol05 - 25.11.2007, 15:08


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
farad
Дата 4.12.2007, 16:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 199
Регистрация: 1.11.2007

Репутация: 3
Всего: 6



Цитата(thomas @  25.11.2007,  13:54 Найти цитируемый пост)
Как ускорить вставку данных?
через ADO.NET и insert - никак. Такой объем данных только через Ж. При работе с SQL Server создаю текстовый файл и потом с помощью BulkInsert делаю импорт данных. Даже с учетом такого гимороя производительность увеличивается на порядки. Такой же подход можно реализовать и в акцессе подняв его в проге через COM. Импорт из текстового файла акцесс делает так же очень на много быстрее... Возможно есть и менее кривые способы, хотелось бы узнать - тоже интересно

PM MAIL   Вверх
unicuum
Дата 5.12.2007, 07:21 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 830
Регистрация: 16.3.2005
Где: Рашка

Репутация: нет
Всего: 8



Насмешили темой smile , порядка 30-40 тысяч строк это много? Вот я на днях 10.5 миллионов строк залил в базу MS Access посредством ADO.NET для умеренных экспериментов, на самом деле можно залить намного больше, просто мне для тестинга хватает, к тому же даже для заливки этих данных пришлось подождать пару часов. Кстати я это делал на Pentium IV 3ГГц и таким способом, что оперативка не расходовалась.

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

tol05, farad, вы не обратили внимание, что thomas использует локальную базу MS Access, а значит серверные базы MS SQL здесь вообще нипричём, в данном случае в ADO.NET применяется OleDB. Вот мне к тому же надо было не только загнать данные в БД, но ещё и выводить их в DataGridView, а там по запросу от 5 до 200 тысяч за раз приходит.

А поступил я достаточно просто, открыл базу, прошёлся 10512000 по циклу и закрыл базу, что иллюстрирует кусок ниже.

Код

Sub InsertToDB(ByRef cn As OleDbConnection, ByRef dt As Date, ByRef gi As Single, ByRef go As Single, ByRef tp As Single)
        Dim cmd As OleDbCommand = cn.CreateCommand()
        cmd.CommandText = "INSERT INTO tblGasPower ( fldTimeData, fldGasInlet, fldGasOutlet, fldTemperature ) SELECT ?, ?, ?, ?;"
        cmd.Parameters.Add("@fldTimeData", OleDbType.Date)
        cmd.Parameters.Add("@fldGasInlet", OleDbType.Single)
        cmd.Parameters.Add("@fldGasOutlet", OleDbType.Single)
        cmd.Parameters.Add("@fldTemperature", OleDbType.Single)
        For i As Integer = 1 To 10512000

            cmd.Parameters("@fldTimeData").Value = dt
            cmd.Parameters("@fldGasInlet").Value = gi
            cmd.Parameters("@fldGasOutlet").Value = go
            cmd.Parameters("@fldTemperature").Value = tp
            cmd.ExecuteNonQuery()

        Next i
End Sub

dt имеет тип Date, gi, go, tp - Single, это аргументы передаваемые для ускорения по ссылке. А чтобы не терять времени базу данных открыл в другом месте, а здесь лишь вызвал то, что мне было нужно. Следующий код иллюстрирует как примерно вызывать такой метод.

Код

        cn.Open()
        InsertToDB(cn, dt, gi, go, tp)
        cn.Close()

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

Суть в следующем, когда программа пишет в базу, то никаких проблем нет, даже если она зависла, все равно не нужна, хотя это кому как. А вот если надо считывать потом в DataGridView, то подвисания просто не приемлимы. И тут на помощь пришёл BackgroundWorker, его можно и для записи использовать, хотя лично у меня не было необходимости.

Не став играться с кучей классов отсоединённых объектов, я просто взял DataTable, и при помощи обработчиков событий объекта класса BackgroundWorker обновлял таблицу из запроса, впоследствии присваивая свойству DataSource объекта DataGridView новую таблицу, сбрасывая по умолчанию старую со всеми данными в мусор.

Следующие куски кода частично показывают функциональность.

часть кода на уровне модуля формы
Код

Friend WithEvents tbl As DataTable


часть кода в обработчике RunWorkerCompleted
Код

        MyDataGridView.DataSource = tbl


часть кода из кнопки вызывающей DoWork, который и вызывает InvokeAsyncSelect
Код

BackgroundWorker1.RunWorkerAsync()


часть кода в InvokeAsyncSelect или говоря по простому в асинхронной выборке из БД
обращаю внимание, что период (начальная и конечная даты) как и выше задаётся параметрами, просто в этом куске для наглядности изменено на строковые значения
Код

            Dim temptbl As New DataTable
            tbl = temptbl

            tbl.BeginLoadData()
            Dim da As New OleDbDataAdapter("SELECT idGasPower as [id], fldTimeData as [Время данных], fldGasInlet as [Входящее давление], fldGasOutlet as [Исходящее давление], fldTemperature as [Температура] FROM tblGasPower WHERE fldTimeData>=#1/1/2008# and fldTimeData<#1/2/2008#;", My.Settings.gaspowerConnectionString)
            da.Fill(tbl)
            tbl.EndLoadData()


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

Кстати сброс в мусор может и не лучший способ, но мне он показался очень быстрым, к тому же благодаря этому MyDataGridView воспринимает таблицу как новый источник, и обновляет всё сам. В целом повторюсь, не буду говорить что такой способ работы хорош, но из 10.5 миллионов записей выборка 5 тысяч делается за пару секунд, ну а вывод 200 тысяч записей секунд за тридцать, на вышеуказанном компьютере, я считаю вполне приемлимым, при этом прога естественно не виснет.

И главное оператива не расходуется по пусту, потому что пытаться закачать в неё всю базу самоубийство. Ну, а вообще, я ещё новичок в базах, потому мне ещё набираться и набираться опыта, чтобы узнать самый эффективный способ работы с ними. И всё вышеперечисленное сделал можно сказать в первый раз, в том числе и асинхронный вызов запроса к БД.

Надеюсь то, что сегодня написал будет кому-нибудь полезным, и плюсик мне плюсик smile не забудьте поставить.


--------------------
user posted image
обычный день на винграде
PM   Вверх
farad
Дата 5.12.2007, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 199
Регистрация: 1.11.2007

Репутация: 3
Всего: 6



Цитата(unicuum @  5.12.2007,  07:21 Найти цитируемый пост)
 плюсик мне плюсик  не забудьте поставить.
рад бы да форум не разрешает. а по теме код аналогичный тому что ты привел вставляет миллион строк около 25 минут. П4 2.2Ггц. Запускал вне отладчика - в отладчике не дождался когда загрузится. Тот же объем данных из текстового файла грузится 2секунды! Так что есть куда стремиться smile
 вот код:

Код

        private void button1_Click(object sender, EventArgs e)
        {
            using (OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=d:\test.accdb;Persist Security Info=False"))
            {
                using (OleDbCommand com = new OleDbCommand("", con))
                {
                    con.Open();
                    com.CommandText = "create table bigtable(id int,stringfield varchar(100)not null,"+
                        "intfield int not null, moneyfield money not null, datefield datetime not null,constraint PK primary key(id));";
                    com.ExecuteNonQuery();
                    
                    com.CommandText = "insert into bigtable(id,stringfield,intfield,moneyfield,datefield)values(?,?,?,?,?);";
                    com.Parameters.Add(new OleDbParameter("p1",OleDbType.Integer));
                    com.Parameters.Add(new OleDbParameter("p2", OleDbType.VarChar));
                    com.Parameters.Add(new OleDbParameter("p3", OleDbType.Integer));
                    com.Parameters.Add(new OleDbParameter("p4",OleDbType.Currency));
                    com.Parameters.Add(new OleDbParameter("p5",OleDbType.Date));
                    DateTime startt, stopt;
                    startt = DateTime.Now;
                    for (int i = 0; i < 1000000; i++)
                    {
                        string s = i.ToString();
                        com.Parameters[0].Value = i;
                        com.Parameters[1].Value = i.ToString();
                        com.Parameters[2].Value = i;
                        com.Parameters[3].Value = i;
                        com.Parameters[4].Value = DateTime.Now;


                        com.ExecuteNonQuery();
                    }
                    stopt = DateTime.Now;
                    MessageBox.Show(startt.ToLongTimeString() + "\n" + stopt.ToLongTimeString());
                }
            }
        }




PM MAIL   Вверх
unicuum
Дата 5.12.2007, 12:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 830
Регистрация: 16.3.2005
Где: Рашка

Репутация: нет
Всего: 8



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

В общем, я провёл исследования, пока что без чтения умных книг и прочих полезных источников.

количество записей в примере - 1 051 200

6   - с транзакцией  без параметров   40%
9  -  с транзакцией  с параметрами     60%    657 секунд (погрешность) + выбор по номеру 642
12 - без транзакции без параметров  80%
15 - без транзакции с параметрами  100%  1040 секунд

1. Вызов параметра не по строке, а по индексу почти не влияет на результат.
2. Использование в конце Select или Values ни на что не влияет.
3. Если убрать параметрический запрос и вместо него поставить фиксированные значения, плюс отменить сами параметры, то скорость возрастает аж на 20%, но в следствии того что параметры всё таки нужны это не имеет значения.
4. Внимание: если поставить транзакцию скорость возрастает на 40%!!!
5. С транзакцией и убиранием параметров скорость возрастает на 60%, но опять же в ущерб параметрам, что неприемлимо.

А вывод, с транзакцией в моём примере в базу записывается 1 051 200 записей за 642 секунды (примерно 11 минут), то есть 1637 зап/сек. Тут следует учитывать что компьютер 2.2 ГГц не 3ГГц, но даже если предположить, что скорость записи пропорциональна частоте процессора (слишком смелое предположение smile ), то на более мощном оно бы работало 18 минут 20 секунд, а это всё же больше чем 11 минут, потому что приведённый farad пример, по сути точно такой же какой показал я, и лишь 40% даваемых транзакцией дают моему алгоритму приемущество, в чём можно убедиться помножив 18 минут 20 секунд на 0.6. smile 

А вот собственно и сам код, как всегда без исключений smile :

Код

Sub InsertToDB(ByRef cn As OleDbConnection, ByRef dt As Date, ByRef gi As Single, ByRef go As Single, ByRef tp As Single)
        Dim cmd As OleDbCommand = cn.CreateCommand()

        Dim tn As OleDbTransaction = cn.BeginTransaction(IsolationLevel.ReadCommitted)
        cmd.Transaction = tn

        cmd.CommandText = "INSERT INTO tblGasPower ( fldTimeData, fldGasInlet, fldGasOutlet, fldTemperature ) SELECT ?, ?, ?, ?;"
        cmd.Parameters.Add("@fldTimeData", OleDbType.Date)
        cmd.Parameters.Add("@fldGasInlet", OleDbType.Single)
        cmd.Parameters.Add("@fldGasOutlet", OleDbType.Single)
        cmd.Parameters.Add("@fldTemperature", OleDbType.Single)
        For i As Integer = 1 To 10512000
            cmd.Parameters("@fldTimeData").Value = dt
            cmd.Parameters("@fldGasInlet").Value = gi
            cmd.Parameters("@fldGasOutlet").Value = go
            cmd.Parameters("@fldTemperature").Value = tp
            cmd.ExecuteNonQuery()
        Next i

        tn.Commit()

End Sub


Жаль, я то надеялся, что код farad окажется быстрее, но нет, ни первый, ни второй пункт себя не оправдали, по скорости он абсолютно такой же. Немного поюзал поисковик, есть какая-то штука INSERT BULK, надо его заюзать и тоже сюда результаты написать.

В любом случае 10 млн записей добавятся примерно за 1 час 40 минут, что очень медленно учитывая что запрос по этим 10 млн идёт со скоростью копирования.

Короче по сравнению с thomas с его 30-40 тысячами это хорошо, даже если бы на 3ГГц компьютере база заполнялась 18 минут, то общая скорость в лучшем случае составляла бы 37 зап/сек, против 1637 зап/сек, что в 44 раза медленней.

А вообще база на 10 512 000 записей занимает 362 мегабайта и копируется секунд этак 18 или 584000 зап/сек, что в 356 раз быстрее от моей транзакции.

Вывод: нужно изучать ускоренное добавление в БД, но я думаю не раньше чем оно реально понадобится.


--------------------
user posted image
обычный день на винграде
PM   Вверх
thomas
Дата 5.12.2007, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент... почти
***


Профиль
Группа: Завсегдатай
Сообщений: 1385
Регистрация: 3.10.2006
Где: " Сказочное королевство"

Репутация: 35
Всего: 65



unicuum, farad
Приветствую.
То что вы тут написали конечно заслуживает внимания. Но и вызывает вопросы.
Для начала приведу пример для теста, который написал tol05.
Код

using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            DateTime startTime = DateTime.Now;
            SqlConnection conn = new SqlConnection("Server=(Local); DataBase=Northwind; user=sa; pwd=1");
            //Создадим таблицу
            conn.Open();
            StringBuilder commandText = new StringBuilder("CREATE TABLE T (");
            for(int i = 0; i < 16; i++)
            {
                commandText.Append("c" + i + " integer");
                if(i < 15)
                {
                    commandText.Append(", ");
                }
            }
            commandText.Append(")");
            SqlCommand command = new SqlCommand(commandText.ToString(), conn);
            command.ExecuteNonQuery();
            conn.Close();
            //Берем только что созланную таблицу из БД для работы
            SqlDataAdapter adapter = new SqlDataAdapter("select * from T", conn);
            //Пусть команды сгенерятся автоматическм
            SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
            
            DataSet ds = new DataSet();
            adapter.Fill(ds, "T");
            DataTable dynamicTable = ds.Tables[0];
            DataRow row;
            for(int i = 0; i < 40000; i++)
            {
                row = dynamicTable.NewRow();
                for(int j = 0; j < dynamicTable.Columns.Count; j++)
                {
                    row[j] = i;
                }
                dynamicTable.Rows.Add(row);
            }
            //Обновляем
            adapter.Update(ds, "T");
            TimeSpan totalTime = DateTime.Now - startTime;
            //Показываем результат
            Text = totalTime.ToString();
        }
    }    
}

Создается пустая таблица в БД. Далее в ДатаСет создается таблица, соответствующая таблице БД и заполняется данными. После этого вызывается метод Update для ДатаАдаптера. И Ву А Ля все данные закачаны в таблицу БД. Приведенные код написан для SQL сервера, но я у себя переделывал его под OleDb.

farad, скорость такая же как и у тебя . Миллион строк за 25 минут, 40 тысяч за минуту (на  моих 1,4 Ггерцах)

А терерь вопросы.

unicuum, 
Из твоего примера я понял, что в таблицу забиваются одни и теже данные 10 миллионов раз.
Код

cn.Open()
InsertToDB(cn, dt, gi, go, tp)
cn.Close()

А что будет если нужно для каждой строки откуда-то уникальные данные считывать? Как это повлияет на скорость? И где ты эти 10 миллионов, готовых к заливке в БД, строк собираешься хранить? Ведь по твоим утверждениям 
Цитата

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

Ведь перед тем как заливать данные в БД их нужно как-то и где-то подготовить(создать, отредактировать). Они не появяться из неоткуда.

При создании темы, я написал что использую команду INSERT для каждой строки. А потом задал вопрос  "Как ускорить вставку данных? ".  Возможно я не совсем развернуто его задал.
Существуют ли другие методы вставить данные в пустую таблицу БД, кроме как INSERT команда?  Можно ли за один раз "всем скопом" вставить данные в таблицу БД, а не построчно?

С наилучшими пожеланиями 


Это сообщение отредактировал(а) thomas - 5.12.2007, 13:35


--------------------
Крепко жму горло, искренне ваш Thomas. (С)vingrad
Некоторые сорта флоры буквально за одно мгновение превращают нас в фауну!
Проблемы негров шерифа не волнуют.
PM MAIL   Вверх
unicuum
Дата 5.12.2007, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 830
Регистрация: 16.3.2005
Где: Рашка

Репутация: нет
Всего: 8



начнём попрядку

Цитата(thomas @  5.12.2007,  13:32 Найти цитируемый пост)
farad, скорость такая же как и у тебя . Миллион строк за 25 минут, 40 тысяч за минуту (на  моих 1,4 Ггерцах)

Там где написано 

Код

for(int i = 0; i < 40000; i++)

поставь
Код

for(int i = 0; i < 10000000; i++)

О результатах доложишь в этот раздел smile 

У меня комп есть Celeron 733 с 128 мегами оперативки, так вот перемолоть 40 тысяч записей ему раз плюнуть.


Цитата(thomas @  5.12.2007,  13:32 Найти цитируемый пост)
А что будет если нужно для каждой строки откуда-то уникальные данные считывать?

Скорость будет точно такая же, просто в InsertToDB введёшь свои аргументы. Заметь, я вообще не писал, что ввожу одинаковые данные, иначе зачем бы мне понадобилась функция с аргументами значений, которые помещаются в БД.

Цитата(thomas @  5.12.2007,  13:32 Найти цитируемый пост)
И где ты эти 10 миллионов, готовых к заливке в БД, строк собираешься хранить?

На диске в файле базы данных smile Я просто подкачиваю оттуда не всё в оперативу, а то что мне нужно в данный момент. Я же уже написал, что DataGridView на 5 тысяч записей обновляется за пару секунд, а если запрос выбирающий записи из 10 млн содержит 200 тысяч, то до обновления в DataGridView приходится ждать аж полминуты, но при этом приложение работает, даже говорит что грузит записи smile

Цитата(thomas @  5.12.2007,  13:32 Найти цитируемый пост)
Можно ли за один раз "всем скопом" вставить данные в таблицу БД, а не построчно?

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

И вообще раз у тебя MS SQL надо точно INSERT BULK попробовать  smile 


--------------------
user posted image
обычный день на винграде
PM   Вверх
farad
Дата 5.12.2007, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 199
Регистрация: 1.11.2007

Репутация: 3
Всего: 6



Цитата(thomas @  5.12.2007,  13:32 Найти цитируемый пост)
Существуют ли другие методы вставить данные в пустую таблицу БД, кроме как INSERT команда?  Можно ли за один раз "всем скопом" вставить данные в таблицу БД, а не построчно?
 имхо стандартными SQL командами низя. BULK INSERT, о чем упоминал unicuum и я предлагал как решение через ж.. доступна только в TSQL(это вообще-то вызов внешней утилиты поставляемой с SQL Server), возможно конечно есть аналоги и в других диалектах, но они не дадут возможности получить универсальное решение... 
PM MAIL   Вверх
thomas
Дата 5.12.2007, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент... почти
***


Профиль
Группа: Завсегдатай
Сообщений: 1385
Регистрация: 3.10.2006
Где: " Сказочное королевство"

Репутация: 35
Всего: 65



Цитата

О результатах доложишь в этот раздел  smile 

Ай-ай кэптэн.  smile 

А плюсик поставишь?  smile  smile  smile 


--------------------
Крепко жму горло, искренне ваш Thomas. (С)vingrad
Некоторые сорта флоры буквально за одно мгновение превращают нас в фауну!
Проблемы негров шерифа не волнуют.
PM MAIL   Вверх
unicuum
Дата 5.12.2007, 19:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 830
Регистрация: 16.3.2005
Где: Рашка

Репутация: нет
Всего: 8



Поставил smile

Добавлено через 4 минуты и 58 секунд
thomas, кстати пока ответ на твой вопрос - использовать транзакцию.


--------------------
user posted image
обычный день на винграде
PM   Вверх
unicuum
Дата 10.12.2007, 00:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 830
Регистрация: 16.3.2005
Где: Рашка

Репутация: нет
Всего: 8



Цитата(thomas @  5.12.2007,  17:50 Найти цитируемый пост)
А плюсик поставишь?

Плюсик я тебе поставил, а о результатах ты так и не доложил smile

Впрочем я и так могу сказать что будет, оперативка закончится и всё, ну на 10 лямах не закончится, так на 100 закончится, так что по любому хана, хотя такой способ записи в БД наверное самый быстрый.

Добавлено через 19 секунд
впрочем я не проверял


--------------------
user posted image
обычный день на винграде
PM   Вверх
D_F_V
Дата 12.12.2007, 02:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 50
Регистрация: 27.3.2007
Где: Vladivostok

Репутация: нет
Всего: 1



Цитата(thomas @  5.12.2007,  13:32 Найти цитируемый пост)
А что будет если нужно для каждой строки откуда-то уникальные данные считывать? Как это повлияет на скорость? И где ты эти 10 миллионов, готовых к заливке в БД, строк собираешься хранить? ... 


Полностью присоединяюсь к вопросу....  
ИМХО 10 мл.. строк реальных данных так быстро ты не обработаешь без расхода памяти... тут или жертвовать памятью, или временем... данные в любом случае от кудато читать надо.. быстрее чем из памяти ты их не прочитаешь ведь так?

Цитата(unicuum @  5.12.2007,  14:29 Найти цитируемый пост)

На диске в файле базы данных smile Я просто подкачиваю оттуда не всё в оперативу, а то что мне нужно в данный момент...


Если будешь подкачивать порциями (1, 10, 100... т.д..) то память конечно расходоваться не будет, но получишь совсем другие результаты по времени.... так что ИМХО тут не все так "красиво" в твоем примере...  smile 





Это сообщение отредактировал(а) D_F_V - 12.12.2007, 02:59
PM MAIL ICQ MSN   Вверх
thomas
Дата 12.12.2007, 17:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент... почти
***


Профиль
Группа: Завсегдатай
Сообщений: 1385
Регистрация: 3.10.2006
Где: " Сказочное королевство"

Репутация: 35
Всего: 65



Приветствую всех.
Вопрос решил.
Процесс тормозило создание соединения с Базой.
Было так
Код

Private Function FillTableDataBase(ByVal sql As String, ByVal dt As DataTable, ByVal bgworker As BackgroundWorker, ByVal e As DoWorkEventArgs) As Integer
        Dim progress, loper As Integer  'om rijen te tellen.
        For Each dr As DataRow In dt.Rows ' выполняю вставку строк в цикле(каждую строку из таблицы в ДС отдельно)
            db.AddSqlParameter("RowId", dr("RowId"))
            For Each adComp In comps
                db.AddSqlParameter(adComp.NamePost, dr(adComp.NamePost))
            Next
            db.DoNonQuery(sql) ' добавляем строку в таблицу БД, как? смотри вставку кода в посте ниже.
            db.ClearSqlParametrs()
            loper += 1
            progress = Convert.ToInt32(loper / count * 100)
            bgworker.ReportProgress(progress)
            If bgworker.CancellationPending Then
                e.Cancel = True
                Exit For
            End If
        Next
        Return loper
    End Function

Этот код вызывается в форме приложения.
А этот код находиться в классе, осуществляющем соединение и работу с БД
Код

Public Sub DoNonQuery(ByVal sql As String)
        Try
            con.Open() ' вот это то и тормозило процесс
            cmd.CommandText = sql
            cmd.ExecuteNonQuery()
        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex.Message, "Fout bij uitvoering van database aanvraag.")
        Finally
            con.Close()
        End Try
    End Sub

Тормоза были в том, что каждый раз при вставке строки открывалось и закрывалось соединение с базой.

Переделал немного класс работы с БД
Код

Public Sub DoNonQuery(ByVal sql As String, ByVal conOpen As Boolean)
        If Not conOpen Then
            Try
                cmd.CommandText = sql
                cmd.ExecuteNonQuery()
            Catch ex As Exception
                System.Windows.Forms.MessageBox.Show(ex.Message, "Fout bij uitvoering van database aanvraag.")
            End Try
        End If
    End Sub

    Public Sub ConnectionOpen()
        con.Open()
    End Sub

    Public Sub ConnectionClose()
        con.Close()
    End Sub

И соответственно изменил код в форме. Теперь сначала открываетм соединение с БД, далее построчно вставляем данные и закрываем соединение.
Код

Private Function FillTableDataBase(ByVal sql As String, ByVal dt As DataTable, ByVal bgworker As BackgroundWorker, ByVal e As DoWorkEventArgs) As Integer
        Dim progress, loper As Integer  'om rijen te tellen.
'открыли соединение
        db.ConnectionOpen()
'далее цикл
        For Each dr As DataRow In dt.Rows
            db.AddSqlParameter("RowId", dr("RowId"))
            For Each adComp In comps
                db.AddSqlParameter(adComp.NamePost, dr(adComp.NamePost))
            Next
            db.DoNonQuery(sql, False)
            db.ClearSqlParametrs()
            loper += 1
            progress = Convert.ToInt32(loper / count * 100)
            bgworker.ReportProgress(progress)
            If bgworker.CancellationPending Then
                e.Cancel = True
                Exit For
            End If
        Next
'закрыли соединение
        db.ConnectionClose()
        Return loper
    End Function

И в результате получили приемлимую скорость выполнения опреации (чуть больше минуты) заполнения таблицы БД данными(33000 адресов) и запись XML файла на основании этой таблицы.

Всем спасибо за участие.

С наилучшими пожеланиями.  smile 


--------------------
Крепко жму горло, искренне ваш Thomas. (С)vingrad
Некоторые сорта флоры буквально за одно мгновение превращают нас в фауну!
Проблемы негров шерифа не волнуют.
PM MAIL   Вверх
unicuum
Дата 12.12.2007, 23:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 830
Регистрация: 16.3.2005
Где: Рашка

Репутация: нет
Всего: 8



Цитата(thomas @  12.12.2007,  17:25 Найти цитируемый пост)
Тормоза были в том, что каждый раз при вставке строки открывалось и закрывалось соединение с базой.

А у меня соединение сразу открывалось в другом месте, потом передавалось процедуре и при выходе из процедуры на уровень выше закрывалось, так что скорости это добавит твоему алгоритму, но не моему.
Цитата(D_F_V @  12.12.2007,  02:48 Найти цитируемый пост)
ИМХО 10 мл.. строк реальных данных так быстро ты не обработаешь без расхода памяти... тут или жертвовать памятью, или временем... данные в любом случае от кудато читать надо.. быстрее чем из памяти ты их не прочитаешь ведь так?

Нужно вынести цикл вне процедуры, и тогда можно будет любые значения записывать, скорость останется примерно такой же, т.е. 10.5 млн строк за 11 минут, но есть сведения, что этот процесс можно ускорить в шесть раз, только я так и не понял как, так как в том примере была битая ссылка. У меня подозрения, что всё таки отсоединёными объектами.
Цитата(D_F_V @  12.12.2007,  02:48 Найти цитируемый пост)
Если будешь подкачивать порциями (1, 10, 100... т.д..) то память конечно расходоваться не будет, но получишь совсем другие результаты по времени.... так что ИМХО тут не все так "красиво" в твоем примере...  smile 

Для той программы которую я писал мой вариант наилучший, то есть там нужно именно присоединённо писать. Ну а для серваков которые гоняют инфу туда сюда, лучше вообще брать MS SQL 2005 и не мучаться, скорость будет как при записи файлов. Красивость тут ни причём, просто нужно выбирать вариант, вот и всё.


--------------------
user posted image
обычный день на винграде
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
stab
mr.DUDA
Exception

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, stab, mr.DUDA, Exception.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Базы данных под .NET | Следующая тема »


 




[ Время генерации скрипта: 0.0700 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.