Задать вопрос
@j238267431

Как загрузить большое количество данных в базу SQLite на React Native?

Добрый день,

есть приложение на React Native которое получает данные из базы данных и показывает на экране
Есть задача сделать приложение работающим off line и для этого буду использовать SQLite
То есть когда есть интернет соединение получать данные и сохранять их в базе SQLite, чтобы если нет сети данные брать из нее.
Но данных много и периодически их надо будет обновлять (синхронизировать) с основной базой и каждый раз циклом проводить проверку думаю займет много времени
Посоветуйте пожалуйста как лучше сделать? Как проверить что есть разница между локальной базой (SQLite) и основной?
Может как-то можно каждый раз когда появляется сеть выгружать дамп из основной базы и загружать ее в базу SQLite?
Какие есть практики реализации работы приложения off line?
  • Вопрос задан
  • 333 просмотра
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ответы на вопрос 3
trapwalker
@trapwalker
Программист, энтузиаст
Добавьте в каждую таблицу поле с таймштампом и ставьте туда свежее значение при создании и каждом апдейте записи. Нужно сделать индекс на это поле, тогда выборка всех изменений в БД от конкретного момента (момента последней репликации) будет извлекаться практически мгновенно. Число запросов будет соответствовать числу таблиц в БД.
Синхронизацию можно делать сколь угодно часто, поскольку изменившихся данных будет не много, а чаще всего их не будет вовсе. Выборка происходит по индексу, а значит очень быстро, особенно если ничего не изменилось.

В локальной БД сохраняйте дату последней репликации в отдельной таблице.
Имейте в виду, что обратная репликация из оффлайн БД в основную уже не будет такой простой. Во-первых нужно что-то придумывать с генерацией идентификаторов для новых записей. Возможно придётся переходить на 16-битные идентификаторы (GUID), чтобы они не пересекались с основной базой.
Ещё нужно понимать, что в оффлайн режиме у вас может оказаться недостоверным время на локальной машине.
Если на локальной машине есть доступ к GPS, то можно снизить число негативных последствий, но не предотвратить их вовсе.
Если вам критично не перепутать время правки записей и первоисточник изменений из-за неточности локального времени, то тут надо будет предпринимать меры для решения этой проблемы, и, есть вероятность, что придётся идти на серьёзные компромиссы.
Если у вас будет много локальных клиентов, которые будут работать в оффлайн-режиме, то ситуация усугубится многократно. Минимизируйте возможность правки общих данных клиентами из оффлайн-режима.

Помните, что GPS сейчас не гарантирует достоверного времени на локальной машине, поскольку в некоторых регионах военное положение, а подразделения РЭБ в куче мест ставят помехи и искажают сигналы со спутников. Часы могут сильно врать.
Ответ написан
Комментировать
@rPman
Все очень зависит от особенностей задачи, объема данных, требований к непрерывности и т.п.

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

Дальнейшие варианты нарушают непрерывность работы сервиса (не всегда это возможно), пусть и кратковременно

* временное отключение индексов, когда новых данных очень много и нагрузка из-за их количество значимей чем нагрузка на процессор и оперативную память, очень часто это дает наилучший прирост в скорости (однократно создать индекс на большой объем данных на порядок быстрее чем обновление индекса на каждую новую запись)

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

* частный случай с предыдущим - перенести базу данных в оперативную память. sqlite работает в ней невероятно быстро (пример реализации, машина останавливается, у провайдера создается новая с тем же диском но большей оперативной памяти, выполняется нужная работа, временная машина удаляется, диск остается).
Как вариант - у меня был эксперимент, на ram диске соседней машины создавался образ файловой системы, этот файл публиковался с помощью nbd (это как iscsi только проще и быстрее), монтировался уже на целевой машине и туда переносилась база данных, это было во времена hdd и давало очень значимый прирост (вместо часов работы - минуты), теперь с ssd такой разницы можно не получить или для этого потребуется быстрее сети, не гигабитные), сразу скажу что сетевые файловые системы типа nfs/samba не рекомендуются, так как привносят кучу накладных расходов из-за возможности немонопольного доступа и просто из-за особенностей реализации (например fflush на nfs сильно замедляет работу по сравнению с локальной, так как работает по разному)

Еще один момент, когда база значительно превышает доступную ram, временная база может быть размещена в файловой системе с отключенным принудительным fflush (т.е. по просит дождаться синхронизации данных а ОС рапортует в тот же момент что все записалось, хотя это не так), реализуется это по разному, начиная с опций файловой системы ext data=writeback, отключения журнала и кончая интересных вариантов у виртуальных машин, такой конфиг может работать сравнимо с оперативной памятью, так как все оперативные данные будут закешированы, но само собой очень уязвим ко сбоям, любая аппаратная проблема или глюк ОС убьют данные максимально неприятным способом, но так как такая машина временная, это не проблема, ведь данные в нее копируются на время обработки.

---
все это к тому, что задачу можно решать таким образом, чтобы исключить или перенести узкое место по ресурсам в другое место, вплодь до кластерных решений (буквально поднимается целый кластер, он запускает обработку, работает считанные минуты и уничтожается)
Ответ написан
Комментировать
mayton2019
@mayton2019
Bigdata Engineer
Я не встречал бесплатных механизмов репликации. Обычно для толстых коммерческих БД типа Oracle продавались коробочные продукты (Streams/GoldenGate) которые требовали знаний на уровне сертификации.

Какие могут быть пути репликации в простом случае. Для таких детских бд как SQLits:

1) Убить всё что локально и скачать все что есть в удаленной БД. На вид выглядит просто. Но неясно
как часто это делать. Что будет триггером для такого события? Очевидно что должна быть золотая середина
между потерпеть еще на старых данных или плюнуть и стартовать обновление которое на мобиле
может затянуться на несколько минут. Вобщем пользователь страдает.

2) Придумать механику инкрементального обновления. Для этого вам будет нужно добавить во все
таблицы поле типа last_update_timestamp (вот примерно как Сергей выше писал) и обновлять только те
записи которые старше максимальной даты которая уже есть. Кроме того надо во второй транзакции
убить те записи которые были удалены в remote. Здесь - посложнее т.к. для убийства мы должны
гарантировать существование PK для всех отслеживаемых таблиц. Мой опыт работы с БД показывает
что там не то что PK там даже и нормализация не всегда делается. Все это как-то выглядит хрупко
как хрустальная ваза и возможно потребует дополнительных индексов которые раньше не требовались
для работы системы. Но при хорошем индексировании триггер можно дергать хоть каждые 15 минут.

В более сложном варианте я-бы предложил реплицировать не SQL протокол а тело самой таблицы.
И вести учет контрольных сумм блоков наподобие дерева Меркла. Но это решение настолько далеко
уходит от React-Native приложух что я-бы сам себе не советовал. Тут еще могут быть трудности с native
представлением SQLite. Неизвестно будет ли такая реплика бинарно-совместима.
Но это будет хотя-бы быстрая реплика.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы