У меня есть структура базы данных;поскольку большая часть этого не имеет значения для нас, я опишу только некоторые соответствующие части.Давайте представим объект Item в качестве примера:
items_table = Table("invtypes", gdata_meta,
Column("typeID", Integer, primary_key = True),
Column("typeName", String, index=True),
Column("marketGroupID", Integer, ForeignKey("invmarketgroups.marketGroupID")),
Column("groupID", Integer, ForeignKey("invgroups.groupID"), index=True))
mapper(Item, items_table,
properties = {"group" : relation(Group, backref = "items"),
"_Item__attributes" : relation(Attribute, collection_class = attribute_mapped_collection('name')),
"effects" : relation(Effect, collection_class = attribute_mapped_collection('name')),
"metaGroup" : relation(MetaType,
primaryjoin = metatypes_table.c.typeID == items_table.c.typeID,
uselist = False),
"ID" : synonym("typeID"),
"name" : synonym("typeName")})
Я хочу добиться некоторых улучшений производительности в слое sqlalchemy / database и у меня есть пара идей: 1) Запрос одного и того же элемента дважды:
item = session.query(Item).get(11184)
item = None (reference to item is lost, object is garbage collected)
item = session.query(Item).get(11184)
Каждый запрос генерирует и выдает SQL-запрос.Чтобы избежать этого, я использую 2 пользовательских карты для объекта элемента:
itemMapId = {}
itemMapName = {}
@cachedQuery(1, "lookfor")
def getItem(lookfor, eager=None):
if isinstance(lookfor, (int, float)):
id = int(lookfor)
if eager is None and id in itemMapId:
item = itemMapId[id]
else:
item = session.query(Item).options(*processEager(eager)).get(id)
itemMapId[item.ID] = item
itemMapName[item.name] = item
elif isinstance(lookfor, basestring):
if eager is None and lookfor in itemMapName:
item = itemMapName[lookfor]
else:
# Items have unique names, so we can fetch just first result w/o ensuring its uniqueness
item = session.query(Item).options(*processEager(eager)).filter(Item.name == lookfor).first()
itemMapId[item.ID] = item
itemMapName[item.name] = item
return item
Я считаю, что sqlalchemy выполняет аналогичное отслеживание объекта, по крайней мере, по первичному ключу (item.ID).Если это произойдет, я могу стереть обе карты (хотя стирание карты имен потребует незначительных изменений в приложении, которое использует эти запросы), чтобы не дублировать функциональность и использовать стандартные методы.Актуальный вопрос: есть ли такая функциональность в sqlalchemy, как получить к ней доступ?
2) Стремительная загрузка отношений часто помогает сохранить множество запросов к базе данных.Скажем, мне определенно понадобится следующий набор свойств item = Item ():
item.group (Group object, according to groupID of our item)
item.group.items (fetch all items from items list of our group)
item.group.items.metaGroup (metaGroup object/relation for every item in the list)
Если у меня есть какой-то идентификатор элемента и еще не загружен элемент, я могу запросить его из базы данных, загружая всеМне нужно: sqlalchemy присоединится к группе, ее элементы и соответствующие метагруппы в рамках одного запроса.Если бы я получал к ним доступ с ленивой загрузкой по умолчанию, sqlalchemy должен был бы выполнить 1 запрос, чтобы получить элемент + 1, чтобы получить группу + 1 * # элементов для всех элементов в списке + 1 * # элементов, чтобы получить метагруппу каждого элемента,что расточительно.
2.1) Но что, если у меня уже есть объект Item, и некоторые свойства, которые я хочу загрузить, уже загружены?Насколько я понимаю, когда я повторно выбираю какой-либо объект из базы данных - его уже загруженные отношения не становятся выгруженными, я прав?
2.2) Если у меня есть объект Item, выбранный, и я хочу получить доступ к егоgroup, я могу просто получить getGroup, используя item.groupID, применяя любые необходимые заявления («items» и «items.metaGroup»).Он должен правильно загрузить группу и ее запрошенные отношения без касания материала элемента.Будет ли sqlalchemy правильно сопоставлять эту извлеченную группу с item.group, чтобы при доступе к item.group он ничего не получал из базовой базы данных?
2.3) Если у меня из базы данных извлечены следующие вещи: originalitem, item.group и некоторая часть элементов из списка item.group.items, некоторые из которых могут иметь загруженную metaGroup, что было бы наилучшей стратегией для завершения структуры данных до того же, что и в приведенном выше списке: повторно выберите группу с помощью ("items", "items.metaGroup") стремятся загрузить или проверить каждый элемент из списка элементов в отдельности, а если элемент или его метагруппа не загружены - загрузить их?Кажется, это зависит от ситуации, потому что, если все уже было загружено некоторое время назад, выдавать такой тяжелый запрос бессмысленно.Предоставляет ли sqlalchemy способ отслеживать, загружено ли какое-то отношение объекта, с возможностью заглянуть глубже, чем просто на один уровень?
В качестве иллюстрации к 2.3 - я могу получить группу с идентификатором 83, охотно выбирая "элементы"и "items.metaGroup".Есть ли способ определить из элемента (который имеет идентификатор группы из 83), загружены ли у него «group», «group.items» и «group.items.metaGroup», с помощью инструментов sqlalchemy (в данном случае всеиз них должны быть загружены)?