如何使用SQLAlchemy从表中选择(或某些)随机行?
这是一个特定于数据库的问题.
我知道PostgreSQL,SQLite,MySQL和Oracle都能够通过随机函数进行排序,因此您可以在SQLAlchemy中使用它:
from sqlalchemy.sql.expression import func, select select.order_by(func.random()) # for PostgreSQL, SQLite select.order_by(func.rand()) # for MySQL select.order_by('dbms_random.value') # For Oracle
接下来,您需要根据所需的记录数限制查询(例如使用.limit()
).
请记住,至少在PostgreSQL中,选择随机记录存在严重的性能问题; 这是关于它的好文章.
如果你正在使用orm并且表不是很大(或者你有缓存的行数),并且你希望它与数据库无关,那么真正简单的方法就是.
import random rand = random.randrange(0, session.query(Table).count()) row = session.query(Table)[rand]
这是作弊,但这就是你使用orm的原因.
有一种简单的方法来提取IS数据库独立的随机行.只需使用.offset().无需拉出所有行:
import random
query = DBSession.query(Table)
rowCount = int(query.count())
randomRow = query.offset(int(rowCount*random.random())).first()
Table是你的表(或者你可以在那里放任何查询).如果你想要几行,那么你可以多次运行它,并确保每一行与前一行不同.
这里有四种不同的变化,从最慢到最快排序.timeit
结果在底部:
from sqlalchemy.sql import func from sqlalchemy.orm import load_only def simple_random(): return random.choice(model_name.query.all()) def load_only_random(): return random.choice(model_name.query.options(load_only('id')).all()) def order_by_random(): return model_name.query.order_by(func.random()).first() def optimized_random(): return model_name.query.options(load_only('id')).offset( func.floor( func.random() * db.session.query(func.count(model_name.id)) ) ).limit(1).all()
timeit
我的Macbook上针对具有300行的PostgreSQL表进行10,000次运行的结果:
simple_random(): 90.09954111799925 load_only_random(): 65.94714171699889 order_by_random(): 23.17819356000109 optimized_random(): 19.87806927999918
您可以很容易地看到使用func.random()
远比将所有结果返回到Python更快random.choice()
.
此外,随着表的大小增加,性能order_by_random()
将显着降低,因为ORDER BY
需要全表扫描而不是COUNT
in optimized_random()
可以使用索引.