Łuk*_*asz 103
这是一个特定于数据库的问题.
我知道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
Run Code Online (Sandbox Code Playgroud)
接下来,您需要根据所需的记录数限制查询(例如使用.limit()
).
请记住,至少在PostgreSQL中,选择随机记录存在严重的性能问题; 这是关于它的好文章.
Dav*_*ick 24
如果你正在使用orm并且表不是很大(或者你有缓存的行数),并且你希望它与数据库无关,那么真正简单的方法就是.
import random
rand = random.randrange(0, session.query(Table).count())
row = session.query(Table)[rand]
Run Code Online (Sandbox Code Playgroud)
这是作弊,但这就是你使用orm的原因.
Guy*_*oft 18
有一种简单的方法来提取IS数据库独立的随机行.只需使用.offset().无需拉出所有行:
import random
query = DBSession.query(Table)
rowCount = int(query.count())
randomRow = query.offset(int(rowCount*random.random())).first()
Run Code Online (Sandbox Code Playgroud)
Table是你的表(或者你可以在那里放任何查询).如果你想要几行,那么你可以多次运行它,并确保每一行与前一行不同.
Jef*_*man 13
这里有四种不同的变化,从最慢到最快排序.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()
Run Code Online (Sandbox Code Playgroud)
timeit
我的Macbook上针对具有300行的PostgreSQL表进行10,000次运行的结果:
simple_random():
90.09954111799925
load_only_random():
65.94714171699889
order_by_random():
23.17819356000109
optimized_random():
19.87806927999918
Run Code Online (Sandbox Code Playgroud)
您可以很容易地看到使用func.random()
远比将所有结果返回到Python更快random.choice()
.
此外,随着表的大小增加,性能order_by_random()
将显着降低,因为ORDER BY
需要全表扫描而不是COUNT
in optimized_random()
可以使用索引.
一些 SQL DBMS,即 Microsoft SQL Server、DB2 和PostgreSQL已经实现了 SQL:2003TABLESAMPLE
子句。在 1.1 版中添加了对 SQLAlchemy 的支持。SYSTEM
它允许使用标准要求的不同采样方法 \xe2\x80\x93和来返回表的样本BERNOULLI
,这会返回表的所需近似百分比。
在 SQLAlchemy 中FromClause.tablesample()
和tablesample()
用于生成TableSample
构造:
# Approx. 1%, using SYSTEM method\nsample1 = mytable.tablesample(1)\n\n# Approx. 1%, using BERNOULLI method\nsample2 = mytable.tablesample(func.bernoulli(1))\n
Run Code Online (Sandbox Code Playgroud)\n与映射类一起使用时有一个轻微的问题:生成的TableSample
对象必须具有别名才能用于查询模型对象:
sample = aliased(MyModel, tablesample(MyModel, 1))\nres = session.query(sample).all()\n
Run Code Online (Sandbox Code Playgroud)\n由于许多答案都包含性能基准,因此我还将在此处包含一些简单的测试。使用 PostgreSQL 中的一个简单表,其中包含大约一百万行和一个整数列,选择(大约)1% 的样本:
\nIn [24]: %%timeit\n ...: foo.select().\\\n ...: order_by(func.random()).\\\n ...: limit(select([func.round(func.count() * 0.01)]).\n ...: select_from(foo).\n ...: as_scalar()).\\\n ...: execute().\\\n ...: fetchall()\n ...: \n307 ms \xc2\xb1 5.72 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 1 loop each)\n\nIn [25]: %timeit foo.tablesample(1).select().execute().fetchall()\n6.36 ms \xc2\xb1 188 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 100 loops each)\n\nIn [26]: %timeit foo.tablesample(func.bernoulli(1)).select().execute().fetchall()\n19.8 ms \xc2\xb1 381 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n在急于使用SYSTEM
采样方法之前,我们应该知道它对页面进行采样,而不是对单个元组进行采样,因此它可能不适合例如小型表,并且如果表是聚集的,则可能不会产生随机结果。
如果使用不允许将样本百分比/行数和种子作为参数传递的方言,以及不允许内联值的驱动程序,则如果这些值是 static ,则将这些值作为文字 SQL 文本传递,或者使用自定义的内联它们SQLA 编译器扩展:
\nfrom sqlalchemy.ext.compiler import compiles\nfrom sqlalchemy.sql import TableSample\n\n@compiles(TableSample)\ndef visit_tablesample(tablesample, self, asfrom=False, **kw):\n """ Compile `TableSample` with values inlined.\n """\n kw_literal_binds = {**kw, "literal_binds": True}\n text = "%s TABLESAMPLE %s" % (\n self.visit_alias(tablesample, asfrom=True, **kw),\n tablesample._get_method()._compiler_dispatch(self, **kw_literal_binds),\n )\n\n if tablesample.seed is not None:\n text += " REPEATABLE (%s)" % (\n tablesample.seed._compiler_dispatch(self, **kw_literal_binds)\n )\n\n return text\n\nfrom sqlalchemy import table, literal, text\n\n# Static percentage\nprint(table("tbl").tablesample(text("5 PERCENT")))\n# Compiler inlined values\nprint(table("tbl").tablesample(5, seed=literal(42)))\n
Run Code Online (Sandbox Code Playgroud)\n