Питон 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
предоставляет ряд функций:[...]
- Данные будут сохранены в собственной записи базы данных.
Это полностью прозрачно для вашего приложения. Ваша первая транзакция будет большой, но последующие транзакции будут записывать изменения только для отдельных элементов по мере их изменения.