Получение случайной строки через SQLAlchemy - PullRequest
67 голосов
/ 13 сентября 2008

Как выбрать (или некоторые) случайные строки из таблицы с помощью SQLAlchemy?

Ответы [ 9 ]

97 голосов
/ 14 сентября 2008

Это очень большая проблема для базы данных.

Я знаю, что 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 выбор случайной записи имеет серьезные проблемы с производительностью; здесь хорошая статья об этом.

22 голосов
/ 24 декабря 2008

Если вы используете orm, а таблица не большая (или у вас есть количество кэшированных строк), и вы хотите, чтобы она была независимой от базы данных, то действительно простой подход:

import random
rand = random.randrange(0, session.query(Table).count()) 
row = session.query(Table)[rand]

Это немного обманывает, но именно поэтому вы используете орм.

17 голосов
/ 16 февраля 2013

Существует простой способ получить случайную строку, независимую от базы данных. Просто используйте .offset (). Не нужно тянуть все строки:

import random
query = DBSession.query(Table)
rowCount = int(query.count())
randomRow = query.offset(int(rowCount*random.random())).first()

Где Table - это ваша таблица (или вы можете разместить там любой запрос). Если вам нужно несколько строк, вы можете просто выполнить это несколько раз и убедиться, что каждая строка не идентична предыдущей.

11 голосов
/ 07 ноября 2015

Вот четыре различных варианта, упорядоченные от самого медленного до самого быстрого. 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() может использовать индекс.

1 голос
/ 07 октября 2018

Некоторые СУБД SQL, а именно Microsoft SQL Server, DB2 и PostgreSQL , внедрили предложение SQL: 2003 TABLESAMPLE. В SQLAlchemy была добавлена ​​поддержка в версии 1.1 . Это позволяет возвращать выборку таблицы, используя различные методы выборки - стандарт требует SYSTEM и BERNOULLI, которые возвращают желаемый приблизительный процент таблицы.

В SQLAlchemy FromClause.tablesample() и tablesample() используются для создания TableSample конструкции:

# Approx. 1%, using SYSTEM method
sample1 = mytable.tablesample(1)

# Approx. 1%, using BERNOULLI method
sample2 = mytable.tablesample(func.bernoulli(1))

При использовании сопоставленных классов есть небольшая ошибка: полученный объект TableSample должен иметь псевдоним, чтобы его можно было использовать для запроса объектов модели:

sample = aliased(MyModel, tablesample(MyModel, 1))
res = session.query(sample).all()

Поскольку многие ответы содержат критерии производительности, я также включу несколько простых тестов. Используя простую таблицу в PostgreSQL с около миллиона строк и одним целочисленным столбцом, выберите (приблизительно) 1% sample:

In [24]: %%timeit
    ...: foo.select().\
    ...:     order_by(func.random()).\
    ...:     limit(select([func.round(func.count() * 0.01)]).
    ...:           select_from(foo).
    ...:           as_scalar()).\
    ...:     execute().\
    ...:     fetchall()
    ...: 
307 ms ± 5.72 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [25]: %timeit foo.tablesample(1).select().execute().fetchall()
6.36 ms ± 188 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [26]: %timeit foo.tablesample(func.bernoulli(1)).select().execute().fetchall()
19.8 ms ± 381 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Прежде чем использовать метод выборки SYSTEM, следует знать, что он выбирает страниц , а не отдельные кортежи, поэтому он может не подойти, например, для небольших таблиц.

0 голосов
/ 15 мая 2018

Это моя функция для выбора случайных строк таблицы:

from sqlalchemy.sql.expression import func

def random_find_rows(sample_num):
    if not sample_num:
        return []

    session = DBSession()
    return session.query(Table).order_by(func.random()).limit(sample_num).all()
0 голосов
/ 14 марта 2017

Это решение, которое я использую:

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
0 голосов
/ 20 января 2014

это решение выберет одну случайную строку

Это решение требует, чтобы первичный ключ назывался 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
0 голосов
/ 14 сентября 2008

Существует несколько способов использования 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

Однако я не знаю ни одного стандартного способа

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...