Питон ZODB: как избежать создания базы данных только с одной большой записью?

Я использую модуль базы данных Python ZODB впервые. Учебное пособие ( http://www.zodb.org/en/latest/tutorial.html) вводит меня в заблуждение относительно определенного аспекта поведения базы данных ZODB: как я могу избежать случайного создания базы данных только с одной очень большой записью? Я объясню шаг за шагом мое приложение, мой текущий подход к базе данных и откуда возникла путаница.


1. Предмет-объект

База данных, которую я хочу сохранить, целиком состоит из объектов -объектов, определенных следующим образом (немного упрощенно):

class Item(Persistent):
    def __init__(self, name, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # 1. Persistent variables
        # ------------------------
        self.__name = name
        self.__myList = PersistentList()   # <- list can hold other Item-objects

        self.__myVar01 = None
        self.__myVar02 = None
        self.__myVar03 = None

        # 2. Non-persistent variables
        # ----------------------------
        self._v_myVar01 = None
        self._v_myVar02 = None
        self._v_myVar03 = None

Визуально представлен следующим образом:


Приложение создает один такой объект Item при запуске. Во время приложения этот объект-объект создаст "потомков" (которые также сами являются объектами-объектами). Этот процесс продолжается некоторое время, так что следующая структура объекта находится в памяти:


Эта конструкция может легко состоять из 20000 объектов-предметов. Поэтому я хочу сохранить их в базе данных.


2. Как сохранить эту структуру в базе данных ZODB

Чтобы сохранить эту структуру Item-объектов в базе данных, я следую следующим инструкциям из учебника:

Хранение предметов
Чтобы сохранить объект в ZODB, мы просто присоединяем его к любому другому объекту, который уже находится в базе данных. Следовательно, корневой объект функционирует как точка привязки к загрузке. Корневой объект предназначен для использования в качестве пространства имен для объектов верхнего уровня в вашей базе данных.
[Цитируется из учебника ZODB http://www.zodb.org/en/latest/tutorial.html ]

Следующие функции создают новую базу данных (начиная с элемента верхнего уровня) и сохраняют ее на жесткий диск:

from ZODB.FileStorage import FileStorage
from ZODB import DB
from persistent import Persistent
import transaction

# Call this function to save the database
# to the harddrive and close it.
# ----------------------------------------
def save_database_and_close():
    transaction.commit()
    conn.close()
    db.close()

# Call this function to create a new
# database, starting from a root-item
# ------------------------------------
def create_database(root_item):
    storage = FileStorage("C:/mytest/mydb.db")
    db = DB(storage)
    conn = db.open()
    root = conn.root()
    root.myRootItem = root_item
    transaction.commit()


3. Проблема с хранением всего в корне

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

(Обратите внимание, что на этом этапе в учебном пособии описан пример создания объектов Account для хранения в базе данных ZODB).

Мы могли бы хранить Account -объекты непосредственно в корневом объекте:

import account

# Probably a bad idea:
root.account1 = account.Account()

Но если вы собираетесь хранить много объектов, вы захотите использовать объект коллекции 3:

import account, BTrees.OOBTree

root.accounts = BTrees.OOBTree.BTree()
root.accounts['account-1'] = Account()

Сноска 3:
Корневой объект - это простой простой постоянный объект, который хранится в одной записи базы данных. Если вы сохраните в нем много объектов, запись в его базе данных станет очень большой, что приведет к неэффективности обновлений и неэффективному использованию памяти.

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


4. Что меня смущает

Хорошо, я уверен, что следующий подход очень плох (и осуждается предупреждением выше):


Но применимо ли это предупреждение (не хранить все в корне) к моему случаю? Как это:

Другими словами, будет ли мой подход создавать базу данных с одной большой записью (очень неэффективно)? Или это создаст хорошую базу данных с одной записью на объект-объект?


Замечания:
Я не уверен, что это актуально, но я перечислю свои системные характеристики здесь:

  • Windows 10, 64-битная
  • Python 3.6.3
  • ZODB 5.4.0 (последняя версия от 21 мая 2018 года)

1 ответ

Решение

Нет, это не неэффективно. ZODB создает отдельные записи для каждого Persistent экземпляр. Эти записи позже загружаются по требованию при доступе к ним.

Из того же учебника, на который вы ссылаетесь:

Наследование Persistent предоставляет ряд функций:

[...]

  • Данные будут сохранены в собственной записи базы данных.

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

Другие вопросы по тегам