Как выбрать (или некоторые) случайные строки из таблицы с помощью SQLAlchemy?
Получение случайной строки через SQLAlchemy
Ответ 1
Это проблема с базой данных.
Я знаю, что PostgreSQL и MySQL имеют возможность упорядочивать случайную функцию, поэтому вы можете использовать это в 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 выбор случайной записи имеет серьезные проблемы с производительностью; здесь - хорошая статья об этом.
Ответ 2
Если вы используете orm, а таблица невелика (или у вас есть количество кэшированных строк), и вы хотите, чтобы она была независимой от базы данных, действительно простой подход.
import random
rand = random.randrange(0, session.query(Table).count())
row = session.query(Table)[rand]
Это немного изменяет, но вот почему вы используете orm.
Ответ 3
Существует простой способ вывести случайную строку, независимую от базы данных. Просто используйте .offset(). Не нужно тянуть все строки:
import random
query = DBSession.query(Table)
rowCount = int(query.count())
randomRow = query.offset(int(rowCount*random.random())).first()
Где Таблица является вашей таблицей (или вы можете поставить туда какой-либо запрос). Если вы хотите несколько строк, вы можете просто запустить это несколько раз и убедиться, что каждая строка не идентична предыдущей.
Ответ 4
Здесь четыре разных вариации, упорядоченные от самых медленных до самых быстрых. 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
результаты для 10 000 запусков на моем Macbook против таблицы PostgreSQL с 300 строками:
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
в optimized_random()
, можно использовать индекс.
Ответ 5
Это решение, которое я использую:
from random import randint
rows_query = session.query(Table) # get all rows
if rows_query.count() > 0: # make sure there 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
Ответ 6
Расширенная версия примера Лукаша, если вам нужно выбрать несколько строк в случайном порядке:
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))
Итак, это сообщение просто указывает, что вы можете использовать .in_ для одновременного выбора нескольких полей.
Ответ 7
это решение выберет одну случайную строку
Это решение требует, чтобы первичный ключ был назван 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
Ответ 8
Существует несколько способов использования 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
Oracle:
SELECT column FROM
(SELECT column FROM table
ORDER BY dbms_random.value)
WHERE rownum = 1
Однако я не знаю какого-либо стандартного способа