SqlAlchemy IntegrityError - PullRequest
       14

SqlAlchemy IntegrityError

4 голосов
/ 22 апреля 2011

Я пытаюсь получить целую кучу данных с Facebook и добавлять объекты в базу данных по мере их обработки.Для лайков, например, я просто делаю их удостоверением личности человека, который издал подобное.Однако, когда я добавлю более одного подобного, я столкнусь с ошибкой целостности в sqlalchemy, потому что первичные ключи не являются уникальными.

Как лучше всего справиться с этим?Нужно ли делать запрос каждый раз, когда я собираюсь добавить новый объект в базу данных, узнать, есть ли он, увеличить его количество, если оно существует, и создать новую запись, если его нет?

Не кажется ли это большим количеством запросов?Как вы думаете, что лучше всего делать?

1 Ответ

6 голосов
/ 22 апреля 2011

Вам действительно нужно оптимизировать его для большой нагрузки?Вероятно, нет, если вы используете SQLite.Простое решение в этом случае намного лучше:

class Like(Base):
    __tablename__ = 'Like'
    id = Column(Integer, primary_key=True)
    counter = Column(Integer, nullable=False, default=0)


o = session.merge(Like(id=1))
session.flush()  # Required when it's new record
o.counter = Like.counter+1
session.commit()

Между проверкой и вставкой существует условие гонки, но я считаю, что на практике это вас не побьет.

Когда вы действительнонужно немного его оптимизировать или исправить это состояние гонки, в SQLite есть INSERT OR IGNORE, чтобы избежать проверки (еще выполняется 2 отдельных оператора):

clause = Like.__table__.insert(prefixes=['OR IGNORE'],
                               values=dict(id=1, counter=0))
session.execute(clause)
o = session.merge(Like(id=1, counter=Like.counter+1))
session.commit()

И, наконец, есть способсделайте это в одном выражении, используя INSERT OR REPLACE и вложенный выбор (есть другие способы сделать это в большинстве других баз данных, например, ON DUPLICATE KEY в MySQL), но я сомневаюсь, что это даст вам заметный прирост производительности:

old = session.query(Like.counter).filter_by(id=1).statement.as_scalar()
new = func.ifnull(old, 0) + 1
clause = Like.__table__.insert(prefixes=['OR REPLACE'],
                               values=dict(id=1, counter=new))
session.execute(clause)
...