Перейти к содержанию
Fire Monkey от А до Я
  • 0

Проблема с выводом большого количества данных SQLite


Павел

Вопрос

Использую БД SQLite, количество записей перевалило за 2000. Понадобилось перебрать все записи и сравнить с каждую запись с другим массивом данных.

Загрузить все данные, а это 2000 с лишним записей сразу не позволяет система, просто ничего не происходит (процедура не исполняется). Поэтому свойство FetchOption.RowsetSize установил 500, свойство FetchOption.Mode установлено в fmOnDemand, т.е.когда обрабатывается порция данных по документации должна быть получена следующая порция данных и так до конца. Однако, на практике при такой конструкции при получении данных, количество данных (RecordCount) приравнивается к св-ву RowsetSize и выводит только 500 записей, а цикл While почему-то не работает, просто ничего не происходит.

Как вывести полный объем данных?

var

DBArray: TStringList;

FQuery: TMySQLiteQuery;

........

SQL := 'SELECT * FROM FileStore';
FQuery.SelectQuery(SQL);
//while (not FQuery.Eof) do
for j := 0 to FQuery.RecordCount - 1 do
begin
     AData := FQuery.Fields.FieldByName('FileName').AsString;
     DBArray.Append(AData);
     FQuery.Next;
end;
ShowMessage(IntToStr(DBArray.Count));

.......

 

 

Изменено пользователем Павел
Ссылка на комментарий

Рекомендуемые сообщения

  • 0
  • Модераторы

Итак, если речь про Андроид, то вы скорее всего поступаете не правильно. База и без вашего массива(клона) висит в памяти, а вы хотите ещё нагрузить... А если записей станет 100 000?! и не известно какая там ещё структура таблицы...
Это я вот к чему, вы же скорее всего сравниваете по какому-то столбцу, так и извлекайте нужный вам столбец, а не все сразу. Далее, я не стал бы извлекать все записи в массив, т.е. создавать клон базы, проще попробовать выполнить запрос по извлечению/поиску конкретной записи и посмотреть на скорость отработки. Мне думается, это будет менее затратно... Не делайте так :) Результаты тестов ниже.

(это моё ИМХО, но другие обоснованные мнения приветствуются :), я тоже бываю не прав...)

Если вы всё же используете свой способ, то воспользуйтесь ключевым словом "Limit".

Справка по  Select (SQLite)

 

А вообще, дайте больше информации:

  • Какая платформа?
  • Какая структура таблицы?
  • Что с чем нужно сравнивать?
Ссылка на комментарий
  • 0

Платформа Windows, однако, я пользуюсь и для Android, разница только в мелочах.

По поводу выгрузки одного поля, так сначала и было,  это я уже после мучений из контекста выдрал, всяко пробовал, но полностью согласен лучше выгрузить 1 столбец, а не все 28. Сразу скажу, даже если выгружаю 1 столбец картина не меняется. И еще, в настройках у меня стоит  FetchOption.Ubidirectional := True, а это значит, что ранее загруженные данные удаляются, а на их место записываются новые, но вот почему-то это и не происходит.

Что касается поиска конкретной записи в БД - хорошая идея, попробую. Только вот если подряд 2000 запросов будет ...., ну все равно попробую.

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

 

По сравнению: в определенной папке лежат файлы, данные по файлам находятся в БД, в ней соответственно описание этих файлов (удобно для поиска и ...). Так вот, в отдельном потоке через определенное время данная папка проверяется на наличие новых файлов и сверятся с БД, чтобы таких файлов не было, при необходимости добавляет в БД, так вот пока записей было не много, все работало, теперь беда.....

 

И беда в чем:

1. Почему то не работает цикл While, т.е. исходя из настроек следующая партия данные должна по требованию быть загружена автоматически. И как я уже определился, использования цикла for .. do в данном случае не подходит. 

2. Даже когда ставлю FQuery.FetchAll, т.е. выгрузить все данные, все равно выгружается только по значению RowsetSize. Ранее RowsetSize у меня был 2000, но тормозило и код стал не исполняться.

Изменено пользователем Павел
Ссылка на комментарий
  • 0

по поводу RecordCount  уже миллион раз говорилось, что это количество сфетченных записей а не количество записей в датасете  и никогда для перебора не используется цикл for

dataset.open;
while not dataset.eof do
begin
...
  dataset.next;
end;
dataset.close;

ручное сравнение записей с массивом данных тоже странный алгоритм для работы с SQL сервером

все должно сводиться к подготовке данных для сервера и дальнейшей уже серверной работы, а не загрузки всей базы в память 512 Мб

Ссылка на комментарий
  • 1
  • Модераторы

В общем, потестил малость, набросал приложение, сканирующее System32.

Дано:

  • 3181 файл (+1 новый для проверки)
  • база с двумя одинаковыми таблицами (по два столбца(id, FileName) в каждой)

Результаты:

  1. Проверка в цикле, каждый раз по запросу "SELECT * FROM tblFileName WHERE FileName = Имя файла", очень накладно получается примерно 4.8 сек. (4758мс)
  2. Проверка с созданием и заполнением временной таблицы и запросом типа такого "select * from `temp` where FileName not in (select FileName from `tblFileName`)", достаточно быстро - 0.4 сек (437мс)
  3. Ваш способ - примерно 2.2 сек. (2168мс)

Важно заметить, что во втором случае, время замерялось на две задачи, заполнение временной таблицы и сравнение, посредством одного запроса в бд. В первом же случае, данные сразу сравнивались, т.е. замерялся цикл запросов(3181 шт.) на выборку.

Выбор очевиден :) Не знаю, что мне взбрело в голову в предыдущем сообщении...)))

По поводу Limit, это ключевое слово позволяет не только ограничивать количество выбираемых данных, но и делать выборку блоками, например по 500 записей за раз (select FileName from `tblFileName` LIMIT 1,500), подошло бы, если бы нужно было извлекать блоками по 500 записей.

вот такой запрос:

    FDQuery2.SQL.Clear;
    FDQuery2.SQL.Add('SELECT * FROM tblFileName');

    FDQuery2.Active := True;
    FDQuery2.Open;

    if not FDQuery2.IsEmpty then
    begin
      FDQuery2.Last;
      mLogs.Lines.Add('Всего записей: ' + FDQuery2.RecordCount.ToString);
      mLogs.Lines.Add('ID последней записи: ' + FDQuery2.FieldByName('ID').AsString);
    end;

    FDQuery2.Close;

Работает без проблем, извлекает сразу все записи.

 

p.s. Тесты проходили на Windows 7 Pro.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...