2015-05-19 14 views
8

sto usando Flask-SQLAlchemy fare una piuttosto grande inserimento di massa di 60k righe. Ho anche una relazione molti-a-molti su questo tavolo, quindi non posso usare db.engine.execute per questo. Prima di inserire, ho bisogno di trovare elementi simili nel database e di modificare l'inserimento in un aggiornamento se viene trovato un elemento duplicato.inserti Bulk con Flask-SQLAlchemy

Potrei fare questo controllo in anticipo, e poi fare un inserto di massa via db.engine.execute, ma ho bisogno della chiave primaria della riga al momento dell'inserimento.

Attualmente, sto facendo un db.session.add() e db.session.commit() su ogni inserto e ottengo un misero 3-4 inserti al secondo.

Ho eseguito un profiler per vedere dove si trova il collo di bottiglia, e sembra che il db.session.commit() stia prendendo il 60% delle volte.

C'è qualche modo che mi permettesse di fare questa operazione più veloce, forse per gruppo si impegna, ma che mi avrebbe dato le chiavi primarie indietro?

Questo è ciò che sembra i miei modelli come:

class Item(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    title = db.Column(db.String(1024), nullable=True) 
    created = db.Column(db.DateTime()) 
    tags_relationship = db.relationship('Tag', secondary=tags, backref=db.backref('items', lazy='dynamic')) 
    tags = association_proxy('tags_relationship', 'text') 

class Tag(db.Model): 
id = db.Column(db.Integer, primary_key=True) 
text = db.Column(db.String(255)) 

La mia operazione di inserimento è gestito in questo modo:

for item in items: 
    if duplicate: 
     update_existing_item 
    else: 
     x = Item() 
     x.title = "string" 
     x.created = datetime.datetime.utcnow() 
     for tag in tags: 
      if not tag_already_exists: 
       y = Tag() 
       y.text = "tagtext" 
       x.tags_relationship.append(y) 
       db.session.add(y) 
       db.session.commit() 
      else: 
       x.tags_relationship.append(existing_tag) 
    db.session.add(x) 
    db.session.commit() 

risposta

2

Forse si dovrebbe cercare di db.session.flush() per inviare i dati al server, il che significa verranno generate tutte le chiavi primarie. Alla fine è possibile db.session.commit() per impegnare effettivamente la transazione.

+0

Modifica 'db.session.commit()' a 'db.session.flush()' e poi facendo 'db.session.commit()' alla fine dà me 10-12 inserti al secondo, più veloce sicuramente, ma non di molto. –

0

Io uso il seguente codice per leggere rapidamente il contenuto di un dataframe panda in SQLite. Si noti che elude le funzionalità ORM di SQLAlchemy. myClass in questo contesto è una classe derivata da db.Model a cui è stato assegnato un tablename. Come il codice di frammenti di menzioni, mi sono adattato

l = df.to_dict('records') 
# bulk save the dictionaries, circumventing the slow ORM interface 
# c.f. https://gist.github.com/shrayasr/5df96d5bc287f3a2faa4 
connection.engine.execute(
    myClass.__table__.insert(), 
    l 
)