从 db 获取数据(至 json)字段时,使用 Flask-SQLAlchemy 提高 python 的速度
Increase speed of python with Flask-SQLAlchemy when getting data (to json) fields from db
假设我有 1000 页和 10000 个标签。数据库的示例结构:
tags = db.Table('tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True),
db.Column('page_id', db.Integer, db.ForeignKey('page.id'), primary_key=True)
)
class Page(db.Model):
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=tags, lazy='subquery',
backref=db.backref('pages', lazy=True))
page_name = db.Column(db.String(20))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
tag_name = db.Column(db.String(20))
我需要得到一个 json,其中包含 page_name 等字段,然后是 tag_name[=25 的列表=] 在每个 page_name 下。只有提到的字段,没有其他内容。
现在我只是像这样循环:
pages_list = []
pages = Page.query.all()
for page in pages:
page_temp = {}
page_name = page.page_name
page_temp['page_name'] = page_name
tags = []
for tag in page.tags:
tags.append(tag.tag_name)
page_temp['tags'] = tags
pages_list.append(page_temp)
#then return pages_list as json
但是,它给了我不希望的加载速度。有没有办法提高这里的速度并得到想要的json?
首先没有必要做pages = Page.query.all()
,因为Page.query
应该是一个迭代器。
它可以缩短您的查询加载时间。
其次,通过使用 lazy='subquery'
,您有额外的查询来为每个 page
获取 tags
。您可以通过设置 lazy=joined
强制让一个查询选择所有 pages
和 tags
(它的文档:https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#joined-eager-loading)。因此,当您执行 page.tags
时,不会命中其他隐式查询(您将有 1 个查询而不是 <number of pages> + 1
查询)。问题是你是不是总是想在获取page
的时候获取tags
?如果没有,您可以在查询端使用 joinedload
:
from sqlalchemy.orm import joinedload
pages_list = []
pages = Page.query.options(joinedload(Page.tags))
for page in pages:
page_temp = {}
page_name = page.page_name
page_temp['page_name'] = page_name
tags = []
for tag in page.tags:
tags.append(tag.tag_name)
page_temp['tags'] = tags
pages_list.append(page_temp)
#then return pages_list as json
呈现包含大量关联标签的 10k 页面结构总是需要一些时间。您可以考虑对这些数据进行分页吗?或者您必须在一个请求中获取它?
假设我有 1000 页和 10000 个标签。数据库的示例结构:
tags = db.Table('tags',
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True),
db.Column('page_id', db.Integer, db.ForeignKey('page.id'), primary_key=True)
)
class Page(db.Model):
id = db.Column(db.Integer, primary_key=True)
tags = db.relationship('Tag', secondary=tags, lazy='subquery',
backref=db.backref('pages', lazy=True))
page_name = db.Column(db.String(20))
class Tag(db.Model):
id = db.Column(db.Integer, primary_key=True)
tag_name = db.Column(db.String(20))
我需要得到一个 json,其中包含 page_name 等字段,然后是 tag_name[=25 的列表=] 在每个 page_name 下。只有提到的字段,没有其他内容。
现在我只是像这样循环:
pages_list = []
pages = Page.query.all()
for page in pages:
page_temp = {}
page_name = page.page_name
page_temp['page_name'] = page_name
tags = []
for tag in page.tags:
tags.append(tag.tag_name)
page_temp['tags'] = tags
pages_list.append(page_temp)
#then return pages_list as json
但是,它给了我不希望的加载速度。有没有办法提高这里的速度并得到想要的json?
首先没有必要做pages = Page.query.all()
,因为Page.query
应该是一个迭代器。
它可以缩短您的查询加载时间。
其次,通过使用 lazy='subquery'
,您有额外的查询来为每个 page
获取 tags
。您可以通过设置 lazy=joined
强制让一个查询选择所有 pages
和 tags
(它的文档:https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html#joined-eager-loading)。因此,当您执行 page.tags
时,不会命中其他隐式查询(您将有 1 个查询而不是 <number of pages> + 1
查询)。问题是你是不是总是想在获取page
的时候获取tags
?如果没有,您可以在查询端使用 joinedload
:
from sqlalchemy.orm import joinedload
pages_list = []
pages = Page.query.options(joinedload(Page.tags))
for page in pages:
page_temp = {}
page_name = page.page_name
page_temp['page_name'] = page_name
tags = []
for tag in page.tags:
tags.append(tag.tag_name)
page_temp['tags'] = tags
pages_list.append(page_temp)
#then return pages_list as json
呈现包含大量关联标签的 10k 页面结构总是需要一些时间。您可以考虑对这些数据进行分页吗?或者您必须在一个请求中获取它?