SQLAlchemy를 통해 임의의 행 가져 오기


답변:


123

이것은 매우 데이터베이스 관련 문제입니다.

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에서는 임의의 레코드를 선택하면 심각한 성능 문제가 있음을 명심하십시오. 여기 에 대한 좋은 기사가 있습니다.


11
+1. Postgres가 SQLite에서 작동하는 것과 동일 : select.order_by(func.random()).limit(n)
mechanical_meat

Oracle에서 order_by ( 'dbms_random.value')를 사용할 수 있습니다.
Buttons840

11
선언적 모델을 사용하는 경우 :session.query(MyModel).order_by(func.rand()).first
trinth

2
내가 마지막에 paranthesis를 추가 할 때 감사 @trinth, 그것은 일 :session.query(MyModel).order_by(func.rand()).first()
켄트 Munthe Caspersen은

3
SQLAlchemy v0.4부터는 func.random()데이터베이스의 임의 구현으로 컴파일되는 일반 함수입니다.
RazerM 2016

25

orm을 사용하고 있고 테이블이 크지 않고 (또는 캐시 된 행의 양이있는 경우) 데이터베이스에 독립적 이길 원하는 경우 정말 간단한 방법입니다.

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

이것은 약간의 속임수이지만 그것이 당신이 orm을 사용하는 이유입니다.


rand = random.randrange (0, session.query (Table) .count ())
James Brady

당신은 전에 중 하나를 선택합니다 선택하고 모든 객체를 생성
서지 K.을

어때요 random.choice(session.query(Table))?
Solomon Ucko 2018

23

데이터베이스에 독립적 인 임의의 행을 가져 오는 간단한 방법이 있습니다. .offset () 사용하십시오. 모든 행을 가져올 필요가 없습니다.

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

테이블은 테이블입니다 (또는 여기에 쿼리를 넣을 수 있음). 몇 개의 행을 원할 경우이를 여러 번 실행하고 각 행이 이전 행과 동일하지 않은지 확인하십시오.


업데이트-mysql의 약 천만 행에서 이것은 실제로 약간 느려지기 시작했습니다.
GuySoft apr

1
~ 500k 행 설정에서 잘 작동합니다.
Mario

1
이제 Oracle에서 1,100 만 행까지 올라갑니다 .... 더 이상 좋지는 않습니다. :-) 선형 저하,하지만 여전히 ... 다른 것을 찾아야합니다.
Mario

2
@Jayme : query.offset(random.randrange(rowCount)).limit(1).first().
jfs

1
@Jayme도 .limit(1)전에 사용하는 이유가 .first()있습니까? 중복 된 것 같습니다. 아마도 query.offset(random.randrange(row_count)).first()충분합니다.
jfs

17

다음은 가장 느린 것부터 가장 빠른 것 순으로 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 내 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().

또한 테이블의 크기가 증가함에 따라의 성능은 전체 테이블 스캔이 필요하지만 in 은 인덱스를 사용할 수 order_by_random()있기 때문에 크게 저하됩니다 .ORDER BYCOUNToptimized_random()


샘플 채취는 어떻습니까? 무엇을 좋아 random.sample()합니까? 여기서 최적화 된 방법은 무엇입니까?
hamidfzm

새 질문을 열고 링크하면 답변을 드릴게요. 가능하면 대답에 영향을 미치는 SQL의 기본 특징을 지정하십시오.
Jeff Widman 2011

사용하지 flask-sqlalchemy않습니까?
MattSom

3

일부 SQL DBMS, 즉 Microsoft SQL Server, DB2 및 PostgreSQL 은 SQL : 2003 TABLESAMPLE절을 구현했습니다 . 버전 1.1에서 SQLAlchemy 에 대한 지원이 추가되었습니다 . 표준은 요구 - 이것은 다른 샘플링 방법을 사용하여 테이블의 예를 반환 허용 SYSTEMBERNOULLI테이블의 원하는 근사 비율을 반환한다.

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 % 샘플을 선택합니다.

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

이것이 내가 사용하는 솔루션입니다.

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

1
이것은 큰 테이블에서 엄청나게 느릴 것입니다. 당신은 모든 단일 행을 잡은 다음 그것을자를 것입니다.
Matthew

1
와우, 이건 좋지 않아요. 테이블 레코드 수를 가져 오는 쿼리가있는 경우 더 나은 방법입니다. 이 작업은 DB가 작은 웹 앱에서 수행되었으며 더 이상 해당 회사와 협력하지 않아서 그다지 할 수 없습니다.
ChickenFeet

0

이것은 테이블의 임의의 행을 선택하는 내 기능입니다.

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()

-1

데이터베이스에서 임의의 질문을 선택할 때이 예제에서 가장 간단한 방법을 사용하십시오.

#first import the random module
import random

#then choose what ever Model you want inside random.choise() method
get_questions = random.choice(Question.query.all())

1. 데이터베이스에 백만 개의 레코드가 있으면 어떻게합니까? 2. 모두 가져 와서 무작위로 선택해야합니까? 비싼 전화가 아닐까요?
Sourav Badami

1
당연히 비용이 많이 드는 호출이지만 그는 "특정 범위의 데이터 또는 특정 키로 임의 쿼리를 만드는 방법"을 묻지 않고 임의 방법 만 요청했습니다. 그래서 제가 대답하고 당신이 언급 한 것을 고려하면 완전히 다른 주제입니다. 가능한 한 간단하게 답변을하려고하여 정확한 문의를 위해서만 명확하게 답변 해 드리겠습니다. 사람들은 더 간단 할 수 있지만 수많은 줄로 대답합니다.
Anas

-2

이 솔루션은 임의의 단일 행을 선택합니다.

이 솔루션을 사용하려면 기본 키의 이름이 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

4
ID에 공백이 있으면 실패합니다.
erickrf 2015 년

-6

사용중인 데이터베이스에 따라 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

그러나 나는 어떤 표준적인 방법도 모른다


7
네. SQL에서 수행하는 방법을 알고 있지만 ( 베타 .stackoverflow.com / questions / 19412 / …에 해당 답변을 게시했습니다 ) SQLAlchemy 특정 솔루션을 찾고있었습니다.
cnu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.