Небольшой вопрос по поводу баз данных с fcl-db

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

Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Небольшой вопрос по поводу баз данных с fcl-db

Сообщение hinst »

Когда получаешь данные с TQuery, TSQLConnection и прочими, вот в экземпляре TQuery вызываешь метод Next. Вопрос вот в чём: при этом все данные получаются все сразу, и я потом только их перебираю, или же они получаются некими порциями, по одной штуке, скажем, а потом освобождаются?
То есть, если у меня в таблице 1000000000...... записей, я их запрошу и начну перебирать, то они все сразу придут и будут все в памяти висеть пока не закроешь query, или они будут по частям приходить, и уже просмотренные будут освобождаться?
hovadur
постоялец
Сообщения: 116
Зарегистрирован: 31.01.2013 15:50:41

Сообщение hovadur »

Я не смотрел именно TSQLQuery (только TZQuery из Zeoslib), но записи должны приходить частями. Сколько записей в одной части задается в TZQuery настройкой FetchRow. Аналогичная настройка должна быть и в TSQLQuery и похоже это PacketRecords.
Просмотренные записи не освобождаются.
Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Сообщение hinst »

Получается как-то немного тупо. Когда в Query перебираешь полученные записи методом Next, то предыдущие уже просмотренные должны освобождаться, к ним же всё равно нельзя вернуться, метода Back или Previous нету
sim-sim
новенький
Сообщения: 11
Зарегистрирован: 27.12.2013 22:44:48

Сообщение sim-sim »

Prior не оно ?

Получается как-то немного тупо
скоко лет уже этому и вроде никто не жаловался...
Данные загружаются порциями (можно и все сразу) и остаются до... того времени пока они Вам не нужны. Как то так. По крайней мере - основы SQl вроде как...
Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Сообщение hinst »

Я вот что имею в виду:::

Код: Выделить всё

var 
  q: TQuery;
begin
  ...
  a := q.FieldByName("a").AsString;
  q.Next;
  a := q.FieldByName("a").AsString;
  q.Next;
  a := q.FieldByName("a").AsString;
  ...

Вот в этом примере результат загружается в переменную a, потом она затирается....
Если я таким образом буду просматривать триллиард записей, то это будет долго, но с памятью проблем быть не должно, так как предыдущие результаты я не храню. Вопрос в том, хранятся ли они где-то на уровне fcl-db? Я не храню предыдущие a, но я не знаю, хранятся ли они где-то в реализации класса TQuery или вообще по логике модулей fcl-db. Надеюсь стало понятно что я имею в виду.

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

Добавлено спустя 1 минуту 42 секунды:
я имею в виду fcl-db предыдущие записи хранит или нет. Понятно по крайней мере что все записи сразу не загружаются. Они загружаются постепенно. Вопрос в том, освобождаются ли они постепенно
sim-sim
новенький
Сообщения: 11
Зарегистрирован: 27.12.2013 22:44:48

Сообщение sim-sim »

если память не изменяет то данные остаются у вас до момента когда коннект OFF (т.е. они не нужны).

Т.е. то что вытянули осталось в датасете... Память "отжираетса" в зависимости от их количества. О "очистке" данных после получения не слышал (и не встречал). Да и по логике - зачем их очищать (вдруг понадобятся). Вот когда конект оф тогда и удаляются данные.

Хотя, может существуют просвещенные более чем я :) Исправите...

памяти при большом количестве записей может не хватить

угу...

Вот в этом примере результат загружается в переменную a, потом она затирается.


Если загружать порциями то не будет никаких "загрузок" памяти.

К примеру: загрузили 100 записей, обработали, полезли за новыми (предварительно "очистив" датасет от предыдущих).

п.с.

основы SQl вроде как

упс: основы баз данных :)
Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Сообщение hinst »

sim-sim писал(а):Если загружать порциями то не будет никаких "загрузок" памяти.
К примеру: загрузили 100 записей, обработали, полезли за новыми (предварительно "очистив" датасет от предыдущих).

Что-то я не понимаю, как это реализовать.
Вот я делаю например запрос select * from Table1; потом делаю query.Next в цикле, а как сделать загрузку по 100 записей, например, я что-то не понимаю. Можно в двух словах плз?
sim-sim
новенький
Сообщения: 11
Зарегистрирован: 27.12.2013 22:44:48

Сообщение sim-sim »

двух словах плз


эээх-ух и ах

Кратко. http://freepascal.ru/article/lazarus/20090720000443/ а более подробно - гугл :)
Аватара пользователя
EmeraldMan
постоялец
Сообщения: 149
Зарегистрирован: 16.10.2008 08:41:51
Откуда: Белгород
Контактная информация:

Сообщение EmeraldMan »

hinst писал(а):Получается как-то немного тупо. Когда в Query перебираешь полученные записи методом Next, то предыдущие уже просмотренные должны освобождаться, к ним же всё равно нельзя вернуться, метода Back или Previous нету

Как так нету?
SQLQuery.Next; SQLQuery.Prior; а так же SQLQuery.First и SQLQuery.Last. Можно воспользоваться ещё и SQLQuery.MoveBy(Num);

Причем обнаружил интересную особенность: бывает, что когда делаешь большую выборку, то SQLQuery.RecordCount показывает явно меньшее кол-во записей. А если выполнить "SQLQuery.Last; SQLQuery.First;", а затем запросить SQLQuery.RecordCount, то покажет точное число.
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Есть-ли возможность получить одной строкой (с разделителями полей) данные текущей записи?
TSQLQuery.GetCurrentRecord(p: pansichar) - может это как-то можно преобразовать в строку?
hovadur
постоялец
Сообщения: 116
Зарегистрирован: 31.01.2013 15:50:41

Сообщение hovadur »

VirtUX писал(а):Есть-ли возможность получить одной строкой (с разделителями полей) данные текущей записи?

Код: Выделить всё

s := '';
for i := 0 to Query.FieldDefs.Count -1 do begin
  if s= '' then
    s := Query.Fields[i].AsString
  else
    s := s + ';' + Query.Fields[i].AsString;
end;
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

2 hovadur я не про это спрашивал. А про:

Код: Выделить всё

for i := 1 to Query.RecordCount do begin
  s += Query.(Record целиком с разделителями полей) + Char(Разделитель записей);
end;
Delete(s, length(s), 1)


Добавлено спустя 2 минуты 33 секунды:
Перерыл код, и закралось подозрение, что TSQLQuery.GetCurrentRecord(p: pansichar) - не реализовано. Т.к кроме как в предке TDataset (begin Result := false; end;), больше переопределений нет :(
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

TQuery вызываешь метод Next. Вопрос вот в чём: при этом все данные получаются все сразу, и я потом только их перебираю, или же они получаются некими порциями, по одной штуке,

Это называется вроде как "window" (сопрягается с БД-курсором) - больное место DB-компонентов. Если вытаскивать все записи - в плюсах имеешь точное количество записей, правильную навигацию и скроллинг - но может не хватить памяти и уведешь комп в крайне тормознутый своппинг ( особенно если таких прожорливых компонентов много).
В MSE, после жалоб на кривой дельфевский скроллинг в БД-гридах и списках - даже пришлось реализовывать оба варианта - если приаттаченные компоненты для корректного скроллинга требуют всех записей, то вытаскиваются все. Если не требуются - вытаскивается и обновляется только "window".

Query.RecordCount

Чрезвычайно медленная операция в FCL-DB, потому что записи здесь, из соображения поддержания "window - представлены связанным списком, и узнать их количество можно только дойдя до последнего элемента этого списка.
Чтобы этого избежать, например в MSE список заменили на динамический массив записей фиксированного размера (вместо строк хранятся их указатели).

Добавлено спустя 57 минут 10 секунд:
SQLQuery.GetCurrentRecord(p: pansichar) - может это как-то можно преобразовать в строку?

Там может быть куча бинарных данных -как их преобразуешь ?

как сделать загрузку по 100 записей,


SQL :

Код: Выделить всё

select * from Table1 OFFSET x LIMIT y;


или "window"

Код: Выделить всё

query.FetchRows := y;

?
MaratIsk
постоялец
Сообщения: 125
Зарегистрирован: 20.08.2009 18:15:20

Сообщение MaratIsk »

hinst писал(а):Получается как-то немного тупо. Когда в Query перебираешь полученные записи методом Next, то предыдущие уже просмотренные должны освобождаться, к ним же всё равно нельзя вернуться, метода Back или Previous нету


unidirectional
wavebvg
постоялец
Сообщения: 355
Зарегистрирован: 28.02.2008 03:57:35

Сообщение wavebvg »

Есть - TDataSet - класс (в общем-то, абстракный), предназначен для именованного доступа к набору данных (никаких связанных списков и прочей ереси для "ускорения" - только структура и данные, которые читаются лишь в тот момент, когда нужны).
TQuery - реализация это доступа с использованием TSQLConnection (естественно, с буферизацией)

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

Если Вы хотите реализовать более "оптимальную" работу с памятью, то придётся разобраться с тем, как устроены эти компоненты и реализовать свой собственный "умный буфер".

Проблема с "неверным" количеством записей возникает для случаев, когда получение данных ещё не завершено (сервер их тоже не загрузил ещё не знает). Фича очень удобна при работе с большими объемами данных (в частности, обеспечивает возможность по индексам получить большую выборку и потом со смаком её тянуть с сервера не вляпываясь в полное зависание базы и прочие недоразумения) или получать только первые данные, когда все сразу они явно не нужны, а сервак тогда сможет обработать намного больше клиентов. Чтобы этого избежать, нужно сразу фечить все данные.
Ответить