Многие ко многим запросы очень медленно в SQLAlchemy - PullRequest
0 голосов
/ 02 июля 2018

У меня есть эта база данных с 3 таблицами, пирогами, персонами и соединением между ними. Пирог может быть приготовлен многими людьми, и человек может сделать много пирогов, так что это очень законный случай.

Я хочу вывести массивную таблицу в следующем формате:

+-------------------------------------------------------
| person_id | person_name | pies
+-------------------------------------------------------
|     1     |    john     | apple, banana, plum, ..
|     2     |    mary     | apple, plum, pineapple, ..
|    ...    |     ...     | ..., ..., ..., ...
|   10000   |    josh     | banana, coconut, ...

В настоящее время я достигаю этого следующим образом:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import random
import time

app = Flask(__name__)
db = SQLAlchemy(app)

person_to_pie_association_table = db.Table(
    'person_to_pie_association_table',
    db.metadata,
    db.Column('pie_id', db.Integer, db.ForeignKey('pie.id')),
    db.Column('person_id', db.Integer, db.ForeignKey('person.id'))
)

class Person(db.Model):
    __tablename__ = 'person'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    age = db.Column(db.Integer)
    pies = db.relationship("Pie", secondary=person_to_pie_association_table, backref="pies")


class Pie(db.Model):
    __tablename__ = 'pie'
    id = db.Column(db.Integer, primary_key=True)
    flavour = db.Column(db.String)
    user_id = db.Column(db.Integer)

db.create_all()

for i in range(1, 10000):
    name = random.choice(['mary', 'mr F', 'harry', 'cathy', 'john']) + str(i)
    person = Person(name=name)
    flavour = random.choice(['banana', 'strawberry', 'apple', 'chocolate']) + str(i)
    pie = Pie(flavour=flavour)
    db.session.add(person)
    db.session.add(pie)
db.session.commit()

pielist = Pie.query.all()

for i in range(1, 10000):
    print(i)
    person = Person.query.get(i)
    person.pies = random.sample(pielist, 5)
    db.session.add(person)
db.session.commit()

persons = Person.query.all()
start = time.time()
for person in persons:
    person.name
middle = time.time()
for person in persons:
    person.pieflavours = ', '.join([pie.flavour for pie in person.pies])
end = time.time()
print(middle - start)  # 0.005s
print(end - middle)  # 38s

Тем не менее, это довольно медленно. Я думаю, это потому, что person.pies выполняется только после того, как на него ссылаются, и он выполняет SQL-запрос, который в общей сложности составляет 10.000 запросов. Я просматривал документацию по SQLAlchemy и другие вопросы SO, но не смог найти удовлетворительного ответа на вопрос, как с этим справиться.

Таким образом, вместо того, чтобы присоединяться на ходу, его нужно соединить заранее. Я также попытался сформулировать запрос следующим образом: Person.query.join(Pie, Person.pies), но результаты были такими же.

Любой совет приветствуется!

1 Ответ

0 голосов
/ 02 июля 2018

Оказывается, в конце концов я выглядел недостаточно хорошо, установив аргумент lazy отношения 'joined', что сделало его в 1000 раз быстрее (в буквальном смысле).

    pies = db.relationship("Pie", secondary=person_to_pie_association_table, backref="pies", lazy='joined')
...