Blu*_*orn 39 python performance orm sqlalchemy
我目前正在玩SQLAlchemy,这真的很整洁.
为了测试,我创建了一个包含我的图片存档的大表,由SHA1哈希索引(删除重复:-)).这是令人印象深刻的快...
为了好玩,我select *在生成的SQLite数据库上做了相同的操作:
session = Session()
for p in session.query(Picture):
print(p)
Run Code Online (Sandbox Code Playgroud)
我希望看到哈希滚动,但它只是继续扫描磁盘.与此同时,内存使用率暴涨,几秒后达到1GB.这似乎来自SQLAlchemy的身份地图功能,我认为它只保留弱引用.
有人可以向我解释一下吗?我认为在写出哈希后会收集每个Picture p!?
Blu*_*orn 52
好吧,我刚刚找到了一种方法来做到这一点.将代码更改为
session = Session()
for p in session.query(Picture).yield_per(5):
print(p)
Run Code Online (Sandbox Code Playgroud)
一次只能加载5张图片.看起来默认情况下查询将一次加载所有行.但是,我还不了解该方法的免责声明.引自SQLAlchemy docs
警告:谨慎使用此方法; 如果多个行中存在相同的实例,则将覆盖最终用户对属性的更改.特别是,通常不可能将此设置与急切加载的集合(即任何lazy = False)一起使用,因为当在后续结果批处理中遇到这些集合时,这些集合将被清除以用于新的加载.
因此,如果在使用ORM时使用yield_per实际上是正确的方法(tm)扫描大量的SQL数据,何时使用它是安全的?
zzz*_*eek 33
这是我通常为这种情况做的事情:
def page_query(q):
offset = 0
while True:
r = False
for elem in q.limit(1000).offset(offset):
r = True
yield elem
offset += 1000
if not r:
break
for item in page_query(Session.query(Picture)):
print item
Run Code Online (Sandbox Code Playgroud)
这避免了DBAPI所做的各种缓冲(例如psycopg2和MySQLdb).如果您的查询具有显式JOIN,它仍然需要被适当地使用,尽管热切加载的集合保证完全加载,因为它们被应用于提供了实际LIMIT/OFFSET的子查询.
我注意到Postgresql几乎和返回大结果集的最后100行一样长,因为它返回整个结果(减去实际的行获取开销),因为OFFSET只是对整个事物进行简单的扫描.
您可以将图片推迟到仅在访问时检索.您可以在逐个查询的基础上执行此操作.喜欢
session = Session()
for p in session.query(Picture).options(sqlalchemy.orm.defer("picture")):
print(p)
Run Code Online (Sandbox Code Playgroud)
或者您可以在映射器中执行此操作
mapper(Picture, pictures, properties={
'picture': deferred(pictures.c.picture)
})
Run Code Online (Sandbox Code Playgroud)
你是怎么做到这里的文档
无论哪种方式执行此操作都将确保仅在访问属性时加载图片.
| 归档时间: |
|
| 查看次数: |
23158 次 |
| 最近记录: |