Конференция "Базы" » Как ускорить запись строк в Access запросом SQL [D7]
 
  • Neiron © (30.10.11 11:11) [0]

    For i:= 0 to 700000 do
     begin
      Application.ProcessMessages;
      PBZagruzka.Position:= i;
      IntTipEda:= Random(2);
      IntXEda:= Random(IntXRazm);
      IntYEda:= Random(IntYRazm);
      DataM.ADOQEda.SQL.Clear;
      DataM.ADOQEda.SQL.Add('INSERT INTO Координаты_еды ([Тип_еды], [Х], [У]) VALUES (' +
                             IntToStr(IntTipEda) + ',' + IntToStr(IntXEda) + ',' + IntToStr(IntYEda) + ')');
      DataM.ADOQEda.ExecSQL;
     end;



    Всем привет! Вот я сделал цикл для записи в базу данных строк со случайно сгенерированными числами. Строк около 700000. Запись происходит долго, понятно конечно что Application.ProcessMessages; тормозит цикл и лучше сделать отдельный поток. Искал как сделать можно запросом запись без цикла и ненашел ничего подобного. Подскажите как можно ускорить это дело или это все что можно выжать из этого? Может какие то настройки еще не сделал запросы посылаю через ADOQuery база данных создана в Access.
  • Омлет © (30.10.11 12:11) [1]
    В INSERT INTO можно передать сразу много строк для записи, а не по одной.
  • Neiron © (30.10.11 12:21) [2]
    можно но на сколько я понял добавлять можно только строки из другой таблицы пачкой сразу. Смысл цикла создать координаты так чтобы они не совпадали были уникальные типа.
  • sniknik © (30.10.11 13:12) [3]
    > понятно конечно что Application.ProcessMessages; тормозит цикл
    и где это таким "понятиям" учат? вызов процедуры делается очень быстро... гораздо быстрее чем например "обслуживание" структур для обработки данных в ADOQuery, которые ты все одно не используешь... и уж точно чем пере создание в цикле, при отсутствии параметров...
  • sniknik © (30.10.11 13:13) [4]
    > только строки из другой таблицы
    из файла.
  • app © (30.10.11 13:47) [5]
    For i:= 0 to 700000 do
    begin
     Application.ProcessMessages;
    {
     PBZagruzka.Position:= i;
     IntTipEda:= Random(2);
     IntXEda:= Random(IntXRazm);
     IntYEda:= Random(IntYRazm);
     DataM.ADOQEda.SQL.Clear;
     DataM.ADOQEda.SQL.Add('INSERT INTO Координаты_еды ([Тип_еды], [Х], [У]) VALUES (' +
                            IntToStr(IntTipEda) + ',' + IntToStr(IntXEda) + ',' + IntToStr(IntYEda) + ')');
     DataM.ADOQEda.ExecSQL;
    }
    end;
    Сколько времени занимает, и сколько если убрать {}
  • Neiron © (30.10.11 14:03) [6]
    упс там фигурные скобки недолжно быть это я забыл убрать когда скопировал в форум. минут 40 идет создание базы. А то что хотел сказать sniknik я не понял...
  • Anatoly Podgoretsky © (30.10.11 14:51) [7]
    Где не должно быть? Ты поставь где я указал и сообщи результат.
    И где идет создание базы?
    Ты вообще о чем говоришь то?
  • sniknik © (30.10.11 15:43) [8]
    > А то что хотел сказать sniknik я не понял...
    чего непонятного?
    по пунктам
    1 - ProcessMessages не занимает времени, нечего на него валить.
    2 - ускорить можно изучив НОРМАЛЬНУЮ работу с базой, используя НОРМАЛЬНЫЕ компоненты (т.е. не ADOTable, не ADOQuery, не ADOStoredProc).
    3 еще больше можно ускорить изучив особенности работы конкретного движка (Jet), в частности загрузку из файла (Text ISAM)

    а пока не хочешь изучать, а "валишь" вину на других... довольствуйся тем что есть.
    и кстати, отдельный поток не поможет. потоки вообще скорости не добавляют, наоборот уменьшают, просто делают работу параллельно основному (ну и какой смысл ее делать так если пользователь ждет окончания действий... ну вот нажал заполнить, и он что на те 3-5 сек которые ему параллельно выделили, на другую задачу переключится? типа на стирание данных? или их редактирование?).
  • Neiron © (30.10.11 16:16) [9]

    > Ты поставь где я указал и сообщи результат.

    Результаты: ProcessMessages примерно 2 секунды все сделал перебрал в цикле 700000 раз переменную тупо, если поставить фигурные скобки как вы показали.
    А если убрать скобки то работает 3 часа почти пока создаст базу данных.

    > И где идет создание базы?


    База данных создается в Microsoft Office Access 2007.


    > ProcessMessages не занимает времени, нечего на него валить.

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


    > ускорить можно изучив НОРМАЛЬНУЮ работу с базой, используя
    > НОРМАЛЬНЫЕ компоненты

    Опять не те компоненты. Вначале ADOTable ненравился в прошлом посте форума делай говорят через SQL запросы... сделал. Теперь опять не те компоненты теперь ADOQuery неподходит. Как тогда запрос то посылать в базу в книгах (Библия Delphe, Дельфи для профессионалов, Фаронов Delphi 7 Программирование баз данных, Delphi 7 на примерах) нет другого способа я невидел :(((

    > изучив особенности работы конкретного движка (Jet), в частности
    > загрузку из файла (Text ISAM)

    Теперь надо в движок лезть новичку и пытатся что то там понять немыслимо сделанное профи. Я так и останусь зеленым и неопытным если буду понять то что еще наверное рано, а может не рано...
  • Anatoly Podgoretsky © (30.10.11 16:24) [10]
    > Neiron  (30.10.2011 16:16:09)  [9]

    Ну так кто тормозит?
    И еще раз, а где создание базы?
  • Neiron © (30.10.11 16:25) [11]

    > И еще раз, а где создание базы?

    Вы хотите более подробный код? Я немогу понять вопрос ваш???
  • Neiron © (30.10.11 16:43) [12]
    Вот полный код при нажатии на кнопку, сама база данных создана вручную в Access и имеет следующие поля:
    Key - ключевое поле, индексированное, счетчик со случайными числами;
    Тип_еды - числовое поле, не индексированное, числовое;
    X - координата положения еды по х для отображеня в PaintBox, поле не индексированное, числовое;
    У - координата положения еды по y для отображеня в PaintBox, поле не индексированное, числовое.


    //Запуск мира по страндартным настройкам
    procedure TGeneralForm.MenuStandNachalaClick(Sender: TObject);
    var
    i, IntTipEda, IntMaxEda, IntXEda, IntYEda: integer;//Временные параметры для настройки мира

    begin
    //Очистка всех данных в компонентах
    SBar.Panels[0].Text:= 'Время мира - 00:00:00';
    SBar.Panels[1].Text:= 'Темп. - 0';
    SBar.Panels[2].Text:= 'Влаж. - 0';
    SBar.Panels[3].Text:= 'Радиация - 0';
    SBar.Panels[4].Text:= 'Клеток - 0';
    SBar.Panels[5].Text:= 'Пищи - 0';
    SBar.Panels[6].Text:= 'Вирусов - 0';
    ListBDeistviaKletki.Items.Clear;
    CBoxViborKletki.Clear;
    CBoxViborKletki.Text:= '0';

    //Запуск базы данных о ДНК всех клеток мира, очистка старой информации
    DataM.ADOQDNK.ConnectionString:= 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' +
                                      ExtractFilePath(Application.ExeName) +
                                      '\База данных Эволюции.mdb' + ';Persist Security Info=False';
    DataM.ADOQDNK.Active:= true;
    DataM.ADOQDNK.SQL.Clear;
    DataM.ADOQDNK.SQL.Add('DELETE FROM ДНК_клеток');
    DataM.ADOQDNK.ExecSQL;
    DataM.ADOQDNK.SQL.Clear;
    DataM.ADOQDNK.SQL.Add('INSERT INTO ДНК_клеток ([№_клетки],[Цвет],[Размер],[Масса],[Жизнь],' +
                           '[Ошибка_копир _ДНК],[Скорость_деления],[Бак_с_Е],[Е_для_деления],' +
                           '[Е_для_сенсора],[Е_для_движения],[№_клеток_в_орган],[№_жгутиков],' +
                           '[Дальн_сенсора],[Скор_движения],[Коор_клетки_Х],[Коор_клетки_У],' +
                           '[Коор_пищи_Х],[Коор_пищи_У],[Действий_клетки]) ' +
                           'VALUES(1, 100, 6, 6, 60, 0, 2, 25, 20, 10, 1, 1, 1, 40, 1, 0, 0, 0, 0, 0)');
    DataM.ADOQDNK.ExecSQL;

    //Запуск базы данных о координатах еды, генерация еды в мире случайным образом, очистка старой информации
    DataM.ADOQEda.ConnectionString:= 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' +
                                      ExtractFilePath(Application.ExeName) +
                                      '\База данных Эволюции.mdb' + ';Persist Security Info=False';
    DataM.ADOQEda.Active:= true;
    DataM.ADOQEda.SQL.Clear;
    DataM.ADOQEda.SQL.Add('DELETE FROM Координаты_еды');
    DataM.ADOQEda.ExecSQL;
    //Получение количества пикселей компонента PaintBox
    IntXRazm:= PBWord.Width;
    IntYRazm:= PBWord.Height;
    //Формула получения кол. пищи в мире
    IntMaxEda:= Trunc((IntXRazm*IntYRazm)/40);
    //Настройка компонента ProgressBar и Label для показа создания еды в мире
    PBZagruzka.Position:= 0;
    PBZagruzka.Max:= IntMaxEda;
    PBZagruzka.Visible:= true;
    LabZagruzka.Visible:= true;
    //Создание базы данных с координатами еды в мире
    For i:= 0 to IntMaxEda do
     begin
      Application.ProcessMessages;
      Edit1.Text:= IntToStr(IntMaxEda) + '/' + IntToStr(i);
      PBZagruzka.Position:= i;
      IntTipEda:= Random(2);
      IntXEda:= Random(IntXRazm);
      IntYEda:= Random(IntYRazm);
      DataM.ADOQEda.SQL.Clear;
      DataM.ADOQEda.SQL.Add('INSERT INTO Координаты_еды ([Тип_еды], [Х], [У]) VALUES (' +
                             IntToStr(IntTipEda) + ',' + IntToStr(IntXEda) + ',' + IntToStr(IntYEda) + ')');
      DataM.ADOQEda.ExecSQL;
     end;
    //Убираем компоненты загрузки
    PBZagruzka.Visible:= false;
    LabZagruzka.Visible:= false;
    //Запуск таймера отображения в PaintBox еды в мире
    TimerWord.Enabled:= true;
    end;

  • sniknik © (30.10.11 17:34) [13]
    > Вначале ADOTable ненравился
    что значит в начале? я тут чуть ли не с начала века за "родные" компоненты борюсь, вместо замен для привыкших к BDE, переходящих с него... ты переходишь?

    > нет другого способа я невидел :(((
    ADODataSet для возвращающих данные запросов/пакетов/процедур, и ADOCommand для командных(не возвращающих) запросов/...

    > Теперь надо в движок лезть новичку
    ну во первых вопрос задан не в "новичках", а во вторых таки да, хочется скорости нужно изучать досконально то, что используешь. в любом деле (вон слышал что даже шоферы на ручной коробке дают лучшие результаты чем на "автомате"... ну, это если знают тонкости. а программирование оно посложнее будет)
  • sniknik © (30.10.11 17:44) [14]
    > Вот полный код при нажатии на кнопку
    вот кстати еще один "тормоз" -
    > PBZagruzka.Position:= i;
    отрисовка 700 тыс раз... а сколько "кубиков" ты видишь  в компоненте?

    + отсутствие компонента коннекта.
  • sniknik © (30.10.11 18:12) [15]
    > то работает 3 часа
    вот, приведенный (более менее) в порядок код.
    procedure TForm1.Button5Click(Sender: TObject);
    var
     i: integer;
     pIntTipEda, pIntXEda, pIntYEda: TParameter;
    begin
     ADOCon.ConnectionString:=
       'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' +
       ExtractFilePath(Application.ExeName) +
       '\База данных Эволюции.mdb' + ';Persist Security Info=False';

     {ADOQDNK.CommandText:= 'DELETE FROM ДНК_клеток';
     ADOQDNK.Execute;

     ADOQDNK.CommandText:=
       'INSERT INTO ДНК_клеток ([№_клетки],[Цвет],[Размер],[Масса],[Жизнь],' +
       '[Ошибка_копир _ДНК],[Скорость_деления],[Бак_с_Е],[Е_для_деления],' +
       '[Е_для_сенсора],[Е_для_движения],[№_клеток_в_орган],[№_жгутиков],' +
       '[Дальн_сенсора],[Скор_движения],[Коор_клетки_Х],[Коор_клетки_У],' +
       '[Коор_пищи_Х],[Коор_пищи_У],[Действий_клетки]) ' +
       'VALUES(1, 100, 6, 6, 60, 0, 2, 25, 20, 10, 1, 1, 1, 40, 1, 0, 0, 0, 0, 0)';
     ADOQDNK.Execute;}


     ADOQEda.CommandText:= 'DELETE FROM Координаты_еды';
     ADOQEda.Execute;

     ADOQEda.CommandText:=
       'INSERT INTO Координаты_еды ([Тип_еды],[X],[Y]) VALUES (:IntTipEda, :IntXEda, :IntYEda)';

     pIntTipEda:= ADOQEda.Parameters.ParamByName('IntTipEda');
     pIntXEda  := ADOQEda.Parameters.ParamByName('IntXEda');
     pIntYEda  := ADOQEda.Parameters.ParamByName('IntYEda');

     for i:= 1 to 70000 do begin
       pIntTipEda.Value:= Random(2);
       pIntXEda.Value  := Random(200);
       pIntYEda.Value  := Random(200);
       ADOQEda.Execute;

       if (i mod 1000) = 0 then Label1.Caption:= IntToStr(i);
       Application.ProcessMessages;
     end;
    end;


    работает примерно 4 мин (без 15 сек), т.е. в 10 больше (700 тыс вместо 70) будет 40 мин.
    и это даже если не "лезть в движок"... просто нормально писать.
  • Neiron © (30.10.11 18:19) [16]

    > что значит в начале? я тут чуть ли не с начала века за "родные"
    > компоненты борюсь, вместо замен для привыкших к BDE, переходящих
    > с него... ты переходишь?


    Я просто хотел поучится с базами данных работать. На одной из веток форму тут я задавал вопрос как с ADOTable в Access сделать еще одно поле, итогом беседы было что SQL типа проще использовать и он универсальный в разных осях по крайней мере в тех которые меня интересуют (Виндовс ХР и Виндовс 7).


    > ADODataSet для возвращающих данные запросов/пакетов/процедур,
    >  и ADOCommand для командных(не возвращающих) запросов/..


    Это че мне еще надо 2 компонента использовать для работы с базой данных своей?


    > вопрос задан не в "новичках"


    Извиняйте в следующий раз не буду тут писать.


    > > Вот полный код при нажатии на кнопкувот кстати еще один
    > "тормоз" -> PBZagruzka.Position:= i;отрисовка 700 тыс раз.
    > .. а сколько "кубиков" ты видишь  в компоненте?


    А как еще то показать юзеру что идет загрузка программы? Везде используют прогресс бары а тут мой тормозит все прямо. Может уменьшить надо количество раз в цикле на обращение к
    PBZagruzka.Position:= i;

    с помощью условия If ... then?


    > + отсутствие компонента коннекта.


    Зачем компонент конекта если в ADOQuery есть тоже самое подключение. Я думаю он лишний, и без него все работает и подключается.
  • sniknik © (30.10.11 18:21) [17]
    > просто нормально писать.
    в смысле, тут вообще то логика отсутствует напрочь... нормально, но "дубово". не делал бы так естественно, а сделал бы что то типа начального наполнения например на 100 записей, а после инсерт "самой в себя" но с подставленными в запрос вычислениями случайных значений... (ведь тут не нужно какихто конкретных)
    время сократится на порядок... т.е. предположительно пару минут на все 700 тыс. и опять в движок лезть не надо, просто думать... вернее нет, сначала нужно знать sql, а после думать как его применять...
  • sniknik © (30.10.11 18:24) [18]
    > Везде используют прогресс бары а тут мой тормозит все прямо.
    везде используют,и обновляют компонент только когда нужно рисовать (новый кубик открылся), а ты примерно 7 тыс раз один и тот же перерисовываешь... думаешь это добавляет программе скорости?
  • Омлет © (30.10.11 18:25) [19]
    > Neiron ©   (30.10.11 12:21) [2]
    > можно но на сколько я понял добавлять можно только строки из другой таблицы пачкой сразу.


    Ну так да. Только создай эту таблицу в текстовом файле, а потом
    insert into table (...) select * from [tmp.txt] in "c:\tmp-location" "Text;HDR=Yes"


    Вроде в msdn всё написано..

    > Смысл цикла создать координаты так чтобы они не совпадали были уникальные типа.

    Что-то у тебя не видно проверки на уникальность.

    И вообше.. Координаты_еды, ms access - это всё зачем вообще? Что за программа?
 
Конференция "Базы" » Как ускорить запись строк в Access запросом SQL [D7]
Есть новые Нет новых   [134431   +9][b:0][p:0.005]