通过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 

但是我不知道任何标准的方法