通过SQLAlchemy获取随机行
如何使用SQLAlchemy从表中select(或某些)随机行?
这是一个特定于数据库的问题。
我知道PostgreSQL和MySQL有能力通过一个随机函数来sorting,所以你可以在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
接下来,您需要通过您需要的logging数限制查询(例如使用.limit()
)。
请记住,至less在PostgreSQL中,select随机logging有严重的性能问题; 这里是关于它的好文章。
如果你使用的是orm并且表格不是很大(或者你的行数已经被caching了)并且你希望它是独立于数据库的,那么真正简单的方法是。
import random rand = random.randrange(0, session.query(Table).count()) row = session.query(Table)[rand]
这是有点作弊,但这就是为什么你使用orm。
有一个简单的方法来拉一个独立于数据库的随机行。 只需使用.offset()。 不需要拉所有行:
import random query = DBSession.query(Table) rowCount = int(query.count()) randomRow = query.offset(int(rowCount*random.random())).first()
哪里表是你的表(或者你可以把任何查询)。 如果你想要几行,那么你可以多次运行这个,并确保每一行都不同于前一行。
这里有四种不同的变化,从最慢到最快sorting。 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()
在我的Macbook上对300行的PostgreSQL表进行10,000次运行的timeit
结果:
simple_random(): 90.09954111799925 load_only_random(): 65.94714171699889 order_by_random(): 23.17819356000109 optimized_random(): 19.87806927999918
你可以很容易地看到使用func.random()
比将所有结果返回给Python的random.choice()
要random.choice()
。
此外,随着表大小的增加, order_by_random()
的性能将显着降低,因为ORDER BY
需要全表扫描,而optimized_random()
的COUNT
可以使用索引。
这是我使用的解决scheme:
from random import randint rows_query = session.query(Table) # get all rows if rows_query.count() > 0: # make sure there's at least 1 row rand_index = randint(0,rows_query.count()-1) # get random index to rows rand_row = rows_query.all()[rand_index] # use random index to get random row
Lukasz示例的增强版,在需要随机select多行的情况下:
import random # you must first select all the values of the primary key field for the table. # in some particular cases you can use xrange(session.query(Table).count()) instead ids = session.query(Table.primary_key_field).all() ids_sample = random.sample(ids, 100) rows = session.query(Table).filter(Table.primary_key_field.in_(ids_sample))
所以,这个post只是指出你可以使用.in_同时select多个字段。
此解决scheme将select一个随机行
这个解决scheme要求主键被命名为id,如果它不是已经存在的话:
import random max_model_id = YourModel.query.order_by(YourModel.id.desc())[0].id random_id = random.randrange(0,max_model_id) random_row = YourModel.query.get(random_id) print random_row
Theres通过SQL的几个方法,取决于使用哪个数据库。
(我认为SQLAlchemy可以使用所有这些)
MySQL的:
SELECT colum FROM table ORDER BY RAND() LIMIT 1
PostgreSQL的:
SELECT column FROM table ORDER BY RANDOM() LIMIT 1
MSSQL:
SELECT TOP 1 column FROM table ORDER BY NEWID()
IBM DB2:
SELECT column, RAND() as IDX FROM table ORDER BY IDX FETCH FIRST 1 ROWS ONLY
甲骨文:
SELECT column FROM (SELECT column FROM table ORDER BY dbms_random.value) WHERE rownum = 1
但是我不知道任何标准的方法