2015-05-19 12 views
8

Używam Flask-SQLAlchemy do wykonania raczej dużej wkładki zbiorczej z 60 tys. Wierszy. Mam również wiele relacji do wielu na tym stole, więc nie mogę do tego użyć db.engine.execute. Przed wstawieniem muszę znaleźć podobne elementy w bazie danych i zmienić wstawkę na aktualizację, jeśli znajdzie się zduplikowany element.Wkładki masowe z kolbą-SQLAlchemy

Mogę wcześniej wykonać tę kontrolę, a następnie wykonać wkładkę zbiorczą za pomocą db.engine.execute, ale potrzebuję klucz podstawowy rzędu po wstawieniu.

Obecnie robię db.session.add() i db.session.commit() na każdej wkładce, a otrzymuję marne 3-4 wkładki na sekundę.

Uruchomiłem profilera, aby zobaczyć, gdzie jest wąskie gardło, i wydaje się, że db.session.commit() zajmuje 60% czasu.

Czy jest jakiś sposób, który pozwoliłby mi przyspieszyć tę operację, być może poprzez zgrupowanie zatwierdzeń, ale które przywróciłyby mi klucze podstawowe?

To co moje modele wygląda następująco:

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)) 

Moja operacja wkładka jest prowadzony tak:

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() 

Odpowiedz

2

Może powinieneś spróbować db.session.flush() do wysyłania danych do serwera, co oznacza, wszystkie klucze podstawowe zostaną wygenerowane. Na koniec możesz db.session.commit(), aby faktycznie zatwierdzić transakcję.

+0

Zmiana 'db.session.commit()' na 'db.session.flush()' 'i wtedy robi db.session.commit()' na koniec daje ja 10-12 wstawek na sekundę, zdecydowanie szybciej, ale nie za dużo. –

0

Korzystam z następującego kodu, aby szybko odczytać zawartość pandas DataFrame w SQLite. Zauważ, że omija funkcje ORM SQLAlchemy. myClass w tym kontekście jest klasą pochodną db.Model, która ma przypisaną nazwę tablicową. Jak wspomina fragmenty kodu, ja dostosowany

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 
) 
Powiązane problemy