наименьший объем памяти, необходимый для сохранения больших python данных в БД - PullRequest
0 голосов
/ 07 апреля 2020

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

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

МАКСИМАЛЬНОЕ ИСПОЛЬЗОВАНИЕ ПАМЯТИ В ТЕЧЕНИЕ JSON СОХРАНЕНИЕ: 966,83 МБ

РАЗМЕР ПОСЛЕ ОТГРУЗКИ json: 81,03 МБ маринованный: 66,79 МБ msgpack: 33,83 МБ

СЖАТИЕ ВРЕМЯ: json: 5,12 с: 11,17 с msgpack: 0,27 с

ВРЕМЯ ДЕКОМПРЕССИИ: json: 2,57 с: 1,66 с msgpack: 0,52 с

СЖАТИЕ МАКСИМАЛЬНОГО ИСПОЛЬЗОВАНИЯ ПАМЯТИ: json сброс: 840,84 МБ, рассылка: 1373,30 МБ, msgpack: 732,67 МБ

DECOMPRESSION MAX MEMORY ИСПОЛЬЗОВАНИЕ: json: 921,41 МБ, рассылка: 1481,25 МБ msgpack: 1006.12MB

msgpack самая производительная библиотека, но декомпрессия также занимает много памяти. Я также попробовал hickle, который, как говорят, потребляет мало памяти, но окончательный размер оказался 800 МБ.

У кого-нибудь есть предложения? Должен ли я просто увеличить предел памяти? может ли mongodb выполнить операцию сохранения с меньшим объемом памяти?

найти под трассировкой стека

Traceback (most recent call last):
  File "/opt/python/bundle/32/app/web_platform/kernel/kernel_worker/web_platform/call_kernel.py", line 139, in start_simulation
    simulation_job_object.save()
  File "/opt/python/bundle/32/app/web_platform/kernel/kernel_worker/web_platform/models.py", line 172, in save
    self.clean_fields()
  File "/opt/python/run/venv/local/lib/python3.6/site-packages/django/db/models/base.py", line 1223, in clean_fields
    setattr(self, f.attname, f.clean(raw_value, self))
  File "/opt/python/run/venv/local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 630, in clean
    self.validate(value, model_instance)
  File "/opt/python/run/venv/local/lib/python3.6/site-packages/jsonfield/fields.py", line 54, in validate
    self.get_prep_value(value)
  File "/opt/python/bundle/32/app/web_platform/kernel/kernel_worker/web_platform/models.py", line 156, in get_prep_value
    return json.dumps(value, **self.encoder_kwargs)
  File "/usr/lib64/python3.6/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib64/python3.6/json/encoder.py", line 202, in encode
    return ''.join(chunks)
MemoryError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/python/run/venv/local/lib/python3.6/site-packages/background_task/tasks.py", line 43, in bg_runner
    func(*args, **kwargs)
  File "/opt/python/bundle/32/app/web_platform/kernel/kernel_worker/web_platform/call_kernel.py", line 157, in start_simulation
    simulation_job_object.save()
  File "/opt/python/bundle/32/app/web_platform/kernel/kernel_worker/web_platform/models.py", line 172, in save
    self.clean_fields()
  File "/opt/python/run/venv/local/lib/python3.6/site-packages/django/db/models/base.py", line 1223, in clean_fields
    setattr(self, f.attname, f.clean(raw_value, self))
  File "/opt/python/run/venv/local/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 630, in clean
    self.validate(value, model_instance)
  File "/opt/python/run/venv/local/lib/python3.6/site-packages/jsonfield/fields.py", line 54, in validate
    self.get_prep_value(value)
  File "/opt/python/bundle/32/app/web_platform/kernel/kernel_worker/web_platform/models.py", line 156, in get_prep_value
    return json.dumps(value, **self.encoder_kwargs)
  File "/usr/lib64/python3.6/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/lib64/python3.6/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib64/python3.6/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
MemoryError

пример моего кода

class Calculation(Model):
        name = db_models.CharField(max_length=120)
        results = JsonNullField(blank=True, null=True)

results = run_calculation()
calculation = Calculation(name="calculation", results=results)
calculation.save()

1 Ответ

1 голос
/ 07 апреля 2020

По сути, вот как я бы сделал это, чтобы уменьшить потребление памяти и повысить производительность:

  1. Загрузка json файла (нет способа его потоковой передачи в python AFAIK)
  2. Разделить массив словарей на более мелкие блоки
  3. Преобразовать блок в объекты
  4. Вызвать bulk_create
  5. Сборщик мусора после каждой l oop итерации
import json
import gc
from myapp.models import MyModel

filename = '/path/to/data.json'
with open(filename, 'r') as f:
    data = json.load(f)
chunk_size = 100
while data:
    chunk = data[:chunk_size]
    data = data[chunk_size:]
    chunk = [ MyModel(**x) for x in chunk ]
    MyModel.objects.bulk_create(chunk)
    gc.collect()

Вы можете играть с chunk_size, чтобы оптимизировать производительность / потребление памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...