문제

SQLAlchemy를 사용하여 테이블에서 임의의 행(또는 일부)을 선택하려면 어떻게 해야 합니까?

도움이 되었습니까?

해결책

이는 데이터베이스와 관련된 문제입니다.

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에서는 무작위 레코드를 선택하면 심각한 성능 문제가 있다는 점을 명심하십시오. 여기 그것에 관한 좋은 기사입니다.

다른 팁

orm을 사용하고 있고 테이블이 크지 않고(또는 캐시된 행의 양이 있음) 데이터베이스 독립적이기를 원하는 경우 정말 간단한 접근 방식이 있습니다.

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

이것은 약간의 부정 행위이지만 이것이 바로 orm을 사용하는 이유입니다.

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

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

Table은 테이블입니다(또는 거기에 쿼리를 넣을 수도 있습니다).몇 개의 행을 원하는 경우 이를 여러 번 실행하고 각 행이 이전 행과 동일하지 않은지 확인하면 됩니다.

가장 느린 것부터 가장 빠른 것 순으로 정렬된 네 가지 변형이 있습니다. 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 300개의 행이 있는 PostgreSQL 테이블에 대해 내 Macbook에서 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().

또한 테이블의 크기가 커질수록 성능이 향상됩니다. order_by_random() 때문에 크게 저하될 것입니다. ORDER BY 전체 테이블 스캔이 필요하지만 COUNT ~에 optimized_random() 인덱스를 사용할 수 있습니다.

일부 SQL DBMS, 즉 Microsoft SQL Server, DB2 및 포스트그레SQL 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% 샘플을 선택합니다.

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 샘플링 방법은 샘플링이라는 것을 알아야 합니다. 페이지, 개별 튜플이 아니므로 예를 들어 작은 테이블에는 적합하지 않을 수 있습니다.

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

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

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

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

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

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

사용되는 데이터베이스에 따라 SQL을 통한 몇 가지 방법이 있습니다.

(어차피 SQLAlchemy는 이 모든 것을 사용할 수 있다고 생각합니다)

MySQL:

SELECT colum FROM table
ORDER BY RAND()
LIMIT 1

포스트그레SQL:

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

그러나 나는 표준 방법을 모른다

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top