PonyORM: What is the most efficient way to add new items to a pony database without knowing which items already exist?

Deadly 提交于 2019-12-05 07:57:53

I'm noticing that by using the name as a primary key, I'm making a query every time I access the entity using an index. When I just let pony pick sequential ids, I don't seem to need to query.

Internally Pony caches sequential primary keys in the same way as a string primary keys, so I think there should be no difference. Each db_session have separate cache (which is called "identity map"). After an object is read, any access by primary key (or any other unique key) within the same db_session should return the same object directly from the identity map without issuing a new query. After the db_session is over, another access by the same key will issue a new query, because the object could be modified in the database by a concurrent transaction.

Regarding your approaches, I think both of them are valid. If a company have just a few location (say, around ten), I'd use the first approach, because it feels more pythonic to me. It is indeed causes N+1 query, but a query which retrieves an object by a primary key is very fast and easy to the server to execute. The code can be expressed a little more compact by using a get method:

@orm.db_session
def add_company(name, locations):
    loc_entities = [Location.get(name=l) or Location(name=l)
                    for l in locations]
    comp = Company(name=name, locations=loc_entities)

The second approach of retrieving all existing locations with a single query looks like a premature optimization to me, but if you create hundreds a companies per second, and each company has hundreds of locations, it may be used.

I know this as the "get or create" pattern, always had to implement it no matter the ORM or language.

This is my "get or create" for Pony.

class GetMixin():
    @classmethod
    def get_or_create(cls, params):
        o = cls.get(**params)
        if o:
            return o
        return cls(**params)


class Location(db.Entity, GetMixin):
    '''A location for a company'''
    name = orm.PrimaryKey(str)
    companies = orm.Set('Company')

The Mixin is explained on the docs.

Then your code will look like this:

@orm.db_session
def add_company(name, locations):
    loc_entities = [Location.get_or_create(name=l) for l in locations]
    comp = Company(name=name, locations=loc_entities)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!