Форум: "Начинающим";
Текущий архив: 2008.01.13;
Скачать: [xml.tar.bz2];
ВнизБыстрый вывод в текстовый файл? Найти похожие ветки
← →
Razrab © (2007-12-10 11:53) [0]Добрый день, коллеги!
Подскажите способ быстрого, непострочного вывода информации в текстовый файл, если таковой вообще возможен в Delphi. Столкнулся со следующей проблемой: вывожу при помощи стандартного построчного вывода в цикле через Writeln() данные из Oracle в текстовый файл. И все бы ничего, но в одном текстовом файле количество строк 300 с лишним тысяч. В результате, создание такого файла у пользователя занимает 1 час с копейками, многовато. Каким образом можно было бы создать текстовый файл не построчно, а одним махом туда запихнуть данные из Select-а?
Заранее благодарю за помощь.
← →
Сергей М. © (2007-12-10 11:58) [1]А можно полюбопытствовать, зачем клиенту понадобился такой файл ?
← →
Razrab © (2007-12-10 12:05) [2]Это sql-файл набора Insert-ov из таблицы - всего более 300.000 Insert-ov. У клиента нет доступа к нашей БД, и он грузит к себе данные просто запуская набор подобных sql-файлов, которые получает по e-mail.
← →
Сергей М. © (2007-12-10 12:13) [3]Показывай в коде, как формируешь файл ..
← →
clickmaker © (2007-12-10 12:30) [4]
> [2] Razrab © (10.12.07 12:05)
> Это sql-файл набора Insert-ov из таблицы - всего более 300.000
> Insert-ov
а импорта-экспорта в Оракле нету? Типа bcp в MS SQL
← →
DrPass © (2007-12-10 12:44) [5]
> Это sql-файл набора Insert-ov из таблицы - всего более 300.
> 000 Insert-ov.
А не слишком ли нездоровый способ? Может, стоит выполнить bulk load? Наверняка ж он и в Оракле есть.
Тем более что 1 час на выгрузку 300000 строк - это скорее в основном не из-за сохранения в файл, а из-за выгрузки данных из БД.
← →
DrPass © (2007-12-10 12:51) [6]Кстати, даже проверил - секунд 20, и при этом еще и с ProcessMessages
procedure TForm1.Button1Click(Sender: TObject);
var
f: Textfile;
i: integer;
begin
AssignFile(f, "c:\txt.txt");
Rewrite(f);
for i := 1 to 300000 do
begin
writeln(f, "Съешь ещё этих мягких французских булочек да выпей чаю!");
Button1.Caption:= IntToStr(i);
end;
CloseFile(f);
end;
← →
palva © (2007-12-10 12:52) [7]Если выводить файл блоками, скажем по 10 кб, то это будет существенно быстрее, чем строками по 80 байт. Сделать это несложно, и вам здесь подскажут, как. Советую, однако, сначала выяснить причину тормозов.
← →
DiamondShark © (2007-12-10 12:57) [8]Тормоза точно не из-за метода доступа к файлу.
Скорее, из-за метода построения строки для записи в файл.
Но это гадание на кофейной гуще. Показывай код.
← →
Razrab © (2007-12-10 14:49) [9]Вот процедура по которой формируется текстовый файл:
procedure outfiles(var F: TextFile; ADOqr: TADOQuery);
var i: integer;
begin
ADOqr.Active := True;
ADOqr.First;
for i := 0 to ADOqr.RecordCount - 1 do
begin
WriteLn(F, ADOqr.FieldByName("LINE").AsString);
ADOqr.Next;
end;
ADOqr.Active := False;
end;
Коннект через ADO. Похоже что тормоза возникают не из-за построчной записи, а из-за построчной проходки запроса. Но как в данном случае еще можно реализовать, ума не приложу?
← →
palva © (2007-12-10 14:57) [10]> Но как в данном случае еще можно реализовать, ума не приложу?
В ADO есть метод Save позволяющий сохранить весь рекордсет в виде XML-файла. Не знаю, будет ли это быстрее. Да еще и обработка этого файла понадобится.
← →
Razrab © (2007-12-10 15:02) [11]А что если данные из базы сначала в массив загонять, а уже после из него построчно писать в файл? Есть еще варианты?
← →
Сергей М. © (2007-12-10 15:03) [12]
> Razrab © (10.12.07 14:49) [9]
> ADOqr.RecordCount
Здесь засада №1
> FieldByName
Здесь №2
← →
Palladin © (2007-12-10 15:07) [13]ADOqr.Active := True;
ADOqr.First; // на кой? думаешь курсор после открытия на последней стоит?
for i := 0 to ADOqr.RecordCount - 1 do // зачем? однопроходный ведь
begin
WriteLn(F, ADOqr.FieldByName("LINE").AsString); // лучше по индексу
ADOqr.Next;
end;
ADOqr.Active := False;
пробуй это
ADOqr.CursorLocation:=clUseServer;
ADOqr.CursorType:=ctOpenForwardOnly;
ADOqr.LockType:=ltReadOnly;
ADOqr.Open;
While Not ADOqr.Eof Do
Begin
WriteLn(f,ADOqr.Fields[индекс].AsString);
ADOqr.Next;
End;
ADOqr.Close;
← →
Palladin © (2007-12-10 15:09) [14]надеюсь никакой контрол у тебя к нему не привязан :)
← →
Razrab © (2007-12-10 15:11) [15]Сергей М.
А что цикл while not ADOQuery.Eof do и обращение к полю по индексу будут быстрее?! %) Или я не так понял Ваш намек?
← →
Palladin © (2007-12-10 15:13) [16]
> Razrab © (10.12.07 15:11) [15]
> обращение к полю по индексу будут быстрее?
ну так надо думать то головой... то ли объекту искать поле по имени в цикле по всем полям сравнением, да еще и с Case-Insentivity, то ли обращатся на прямую к полю в массиве
← →
{RASkov} © (2007-12-10 15:15) [17]> [15] Razrab © (10.12.07 15:11)
Лучше ответь на [14])
Может у тебя грид скролится во время вывода....
← →
Razrab © (2007-12-10 15:18) [18]Palladin
> надеюсь никакой контрол у тебя к нему не привязан :)
Ну как? Сам коннект работает через ADOConnection и ADOQuery, размещенные на форме. Поскольку запросы весьма громоздкие, то в ADOQuery Select-ы занесены в свойство SQL, чтобы кучу всяких кавычек не ставить.
← →
Сергей М. © (2007-12-10 15:19) [19]
> Razrab © (10.12.07 15:11) [15]
По поводу RecordCount - свойство возвращает гарантированно правильный результат только в том случае, если предварительно был выполнен метод Last.
По поводу обращения к объекту-полю по индексу - да, и ощутимо.
← →
Palladin © (2007-12-10 15:20) [20]
> Razrab © (10.12.07 15:18) [18]
имеется ввиду XXXDBGrid семейство
← →
Palladin © (2007-12-10 15:22) [21]
> Сергей М. © (10.12.07 15:19) [19]
отнюдь не всегда... во первых провайдер должен поддерживать его, во вторых зависит от кучи (ну на самом деле не такой уж и большой кучи) настроек соединения и объекта RecordSet, например в указанных в моем примере настройках RecordSet"а RecordCount не вернется... по крайней мере это справедливо для Jet и MSSQL
← →
Palladin © (2007-12-10 15:24) [22]да и вообще, если честно, на него вообще полагаться не стОит :) и пользоваться тоже... если конечно не затачивать программу под конкретный провайдер
← →
Razrab © (2007-12-10 15:25) [23]Palladin
А почему while то быстрее чем for?
← →
DiamondShark © (2007-12-10 15:26) [24]
> Razrab © (10.12.07 15:25) [23]
> Palladin
>
> А почему while то быстрее чем for?
Он не быстрее, он правильнее.
Как тебе уже сказали, RecordCount после открытия не обязан возвращать точное количество записей.
← →
{RASkov} © (2007-12-10 15:27) [25]> [23] Razrab © (10.12.07 15:25)
Не быстрнее....
Только если ты не заметил, то разговор не об этом....)
← →
Razrab © (2007-12-10 15:27) [26]Palladin
DBGrid-ов у меня нет.
← →
sniknik © (2007-12-10 15:27) [27]> надеюсь никакой контрол у тебя к нему не привязан :)
неважно, посмотри реализацию компонент, при явном отключении проверка на одном, верхнем уровне, при отсутствии контрола "на пару этажей ниже".
и раз уж идет борьба за скорость...
в общем советую в любом случае отключать. как и сменить ADOQuery на ADODataSet... советую, советую... а толку нет.
← →
{RASkov} © (2007-12-10 15:29) [28]> [26] Razrab © (10.12.07 15:27)
Усё равно DisableControls не помешает)
← →
Razrab © (2007-12-10 15:46) [29]И еще, не пойму как иногда вообще без RecordCount обходиться?! %) Ведь скажем, при выводе в тот же Excel, у которого ограничение на 65000 строк на лист, куда быстрее после Open узнать кол-во записей сразу по RecordCount, нежели перед одним полным Select-ом еще и Select Count(*) выдавать. Смысл?
← →
DrPass © (2007-12-10 15:53) [30]
> Сергей М. © (10.12.07 15:19) [19]
>
> > Razrab © (10.12.07 15:11) [15]
>
>
> По поводу RecordCount - свойство возвращает гарантированно
> правильный результат только в том случае, если предварительно
> был выполнен метод Last.
У ADODataset оно, в отличие от других датасетов, все-таки показывает именно количество записей в наборе, а не количество выфетченных записей. Насколько я знаю, потому что ADODataset в двунаправленном режиме не поддерживает страничный фетч, а сразу тупо фетчит на себя весь датасет.
← →
DrPass © (2007-12-10 15:55) [31]
> Ведь скажем, при выводе в тот же Excel, у которого ограничение
> на 65000 строк на лист, куда быстрее после Open узнать кол-
> во записей сразу по RecordCount
Не вижу связи первого со вторым
← →
Palladin © (2007-12-10 15:58) [32]
> Razrab © (10.12.07 15:46) [29]
Ты не представляешь на сколько редки подобные ситуции и в связи с их редкостью абсолютно не в падлу сделать count(*)
← →
Сергей М. © (2007-12-10 16:04) [33]
> DrPass © (10.12.07 15:53) [30]
Сегодня ADODataset, завтра еще какой-нить XXXDataset - рано или поздно грабли выстрелят. Именно на этом я и заострил внимание во фразе "засада №1".
Ни более ни менее. Работает оно сейчас у Автора - да ну и слава богу)
← →
Palladin © (2007-12-10 16:08) [34]
> sniknik © (10.12.07 15:27) [27]
когда то замерял
ADOQuery и ADODataSet на MSSQL и Jet, абсолютно равны по производительности, при ltReadOnly,clUseServer и ctOpenForwardOnly
:) более того на Jet если делать просто тупой цикл
While Not q.Eof Do q.Next;
ADOQuery в два раза быстрее :) ну это понятно ерунда хоть и прикольно... :)
← →
DrPass © (2007-12-10 16:51) [35]
> ADOQuery и ADODataSet на MSSQL и Jet, абсолютно равны по
> производительности
Логично, т.к. первый класс от второго отличается только тем, что CommandText выведен в свойство SQL, в остальном они тождественны
← →
Razrab © (2007-12-10 16:57) [36]Спасибо, коллеги, ВСЕМ кто пытался помочь и реально помог, сейчас все заработало практически со скоростью самих запросов! :) А лекарство вот, напоминаю вышеприведеннный уважаемым Palladin-ом код:
ADOqr.CursorLocation:=clUseServer;
ADOqr.CursorType:=ctOpenForwardOnly;
ADOqr.LockType:=ltReadOnly;
ADOqr.Open;
While Not ADOqr.Eof Do
Begin
WriteLn(f,ADOqr.Fields[индекс].AsString);
ADOqr.Next;
End;
ADOqr.Close;
Так что, если еще кто на подобные грабли наступит ответ готов и выделен жирным. ;)
← →
slavakaram (2007-12-10 17:13) [37]Есть бесплатный компонент kbMemTable - Потомок Dataset. Можно воспользоваться им. Единственно, что он возможно выводит все в CSV-формате, потому максимум 65536 строк. Но зато быстро
← →
Razrab © (2007-12-10 17:17) [38]Palladin
> Ты не представляешь на сколько редки подобные ситуции и
> в связи с их редкостью абсолютно не в падлу сделать count(*)
У нас как раз бывает частенько. :) Юзер хочет видеть данные из БД в Excel, при это заранее даже не задумываясь об их количестве и естественно ограничении самого Excel. Выполнение трехэтажного Select для вывода таких данных порой может доходить до 30-40 минут. Если еще запустить count(*) на такой же промежуток времени, они очумеют. :) Поэтому предпочитаю RecordCount, благо дело под Oracle он вроде без проблем работает.
← →
Palladin © (2007-12-10 17:19) [39]
> Razrab © (10.12.07 17:17) [38]
так решается просто...
прямо в запросе select top 65000
← →
Razrab © (2007-12-10 17:28) [40]В Oracle top нет. Там можно правда через Rownum вложенно выводить от сих до сих. Но я когда увидел, что RecordCount работает, сделал через него. Правда выше уже коллеги напугали, мол до поры до времени. %) Ну на всякий случай буду иметь в виду. :)
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2008.01.13;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.008 c