从MySQL随机选取数据

--从MySQL随机选取数据

-------------------------2014/06/23

 

从MySQL随机选取数据最简单的办法就是使用”ORDER BY RAND()”;

方案一:

[php] view plaincopy
 
  1. SELECT * FROM `table` ORDER BY RAND() LIMIT 0,1;  


这种方法的问题就是非常慢。原因是因为MySQL会创建一张零时表来保存所有的结果集,然后给每个结果一个随机索引,然后再排序并返回。

有几个方法可以让它快起来。

基本思想就是先获取一个随机数,然后使用这个随机数来获取指定的行。

由于所有的行都有一个唯一的id,我们将只取最小和最大id之间的随机数,然后获取id为这个数行。为了让这个方法当id不连续时也能有效,我们在最终的查询里使用”>=”代替”=”。

为了获取整张表的最小和最大id,我们使用MAX()和MIN()两个聚合函数。这两个方法会返回指定组里的最大和最小值。在这里这个组就是我们表里的所有id字段值。

方案二:

[php] view plaincopy
 
  1. $range_result = mysql_query( " SELECT MAX(`id`) AS max_id , MIN(`id`) AS min_id FROM `table` ");  
  2. $range_row = mysql_fetch_object( $range_result );  
  3. $random = mt_rand( $range_row->min_id , $range_row->max_id );  
  4. $result = mysql_query( " SELECT * FROM `table` WHERE `id` >= $random LIMIT 0,1 ");   


就像我们刚才提到的,这个方法会用唯一的id值限制表的每一行。那么,如果不是这样情况怎么办?

下面这个方案是使用了MySQL的LIMIT子句。LIMIT接收两个参数值。第一个参数指定了返回结果第一行的偏移量,第二个参数指定了返回结果的最大行数。偏移量指定第一行是0而不是1。

为了计算第一行的偏移量,我们使用MySQL的RAND()方法从0到1之间生成一个随机数。然后我们把这个数字跟我们用COUNT()方法获取倒的表记录数相乘。由于LIMIT的参数必须是int型而不能是float,我们使用FLOOR()来处理结果。FLOOR()会计算小于表达式的最大值。最终的代码就是这样:

方案三:

[php] view plaincopy
 
  1. $offset_result = mysql_query( " SELECT FLOOR(RAND() * COUNT(*)) AS `offset` FROM `table` ");  
  2. $offset_row = mysql_fetch_object( $offset_result );  
  3. $offset = $offset_row->offset;  
  4. $result = mysql_query( " SELECT * FROM `table` LIMIT $offset, 1 " );  


在MySQL 4.1以后我们可以使用子子查询合并上面两个方法:

方案四:

[php] view plaincopy
 
  1. SELECT * FROM `table` WHERE id >= (SELECT FLOOR( MAX(id) * RAND()) FROM `table` ) ORDER BY id LIMIT 1;  


这个方案跟方案二有同样的弱点,只对有唯一id值的表有效。

记住我们最初寻找选择随机行的替代方法的原因,速度!所以,这些方案的在执行时间上的比较会怎么样?我不会指出硬件和软件配置或者给出具体的数字。大概的结果是这样的:

  • 最慢的是解决方案一(我们假定它用了100%的时间)。
  • 方案二用了79%
  • 方案三 - 13%
  • 方案四 - 16%

方案三胜出!

 

转载于:https://www.cnblogs.com/jackhub/p/3804358.html

<think>好的,我现在需要帮助用户了解如何使用 SQLAlchemy 从 MySQL随机获取10000条数据。首先,我得回忆一下 SQLAlchemy 的基本用法,以及如何在 MySQL 中实现随机数据的功能。 用户的问题是关于随机数据的,所以首先想到的是 MySQL 中的 ORDER BY RAND() 方法。不过我记得这种方法在大数据量下可能会有性能问题,因为需要对整个表进行随机排序,当数据量很大时,效率会很低。不过用户只需要取10000条,如果数据表不是特别大,可能还可以接受。但如果表很大,这种方法可能不太合适,需要考虑其他优化方法。 接下来,我需要考虑如何通过 SQLAlchemy 来实现这个查询。SQLAlchemy 的 ORM 或者 Core 都可以使用。用户可能更倾向于 ORM 的方式,因为那更常见。不过两种方法都应该介绍一下,让用户有选择的空间。 对于 ORM 方式,首先需要定义模型类,或者使用自动映射。然后构建查询,使用 order_by(func.random()) 来生成 ORDER BY RAND(),然后使用 limit(10000) 来限制结果数量。需要注意 MySQL 的 RAND() 函数在 SQLAlchemy 中可能需要用 func.rand(),因为不同的数据库函数名称可能不同。例如,PostgreSQL 使用 RANDOM(),而 MySQL 使用 RAND(),所以正确的函数引用应该是 func.rand()。 然后,执行查询并获取结果。这里要注意的是,当数据量很大时,使用 ORDER BY RAND() 可能会非常慢,因为需要为每一行生成一个随机数并排序。对于这种情况,可能需要考虑其他方法,比如先获取最大ID,然后生成随机ID范围,或者使用预先计算的随机列,但这些方法可能比较复杂,并且可能不适用于所有情况,特别是当数据有删除或ID不连续的时候。 另外,用户可能需要分批次处理数据,或者使用更高效的随机抽样方法。例如,如果知道表的总行数,可以生成随机偏移量,然后使用 LIMIT 和 OFFSET,但这种方法在需要随机选取多个行时可能不够均匀,不过对于大数据量可能更高效。 不过用户明确要求的是随机取10000条,所以可能需要权衡性能和准确性。如果用户的数据量不大,直接使用 ORDER BY RAND() 加 LIMIT 是可行的;如果数据量很大,可能需要建议其他优化方法。 在代码示例中,我需要确保使用正确的函数,比如 func.rand(),并且在连接数据库时使用正确的 MySQL 连接字符串。例如,使用 pymysql 作为驱动,连接字符串格式是 mysql+pymysql://... 另外,还需要提醒用户注意性能问题,特别是当表中数据量超过百万时,ORDER BY RAND() 可能会非常慢。这时候可能需要建议替代方案,比如使用应用程序端的随机抽样(比如先获取所有ID,随机选择,再查询具体数据),或者使用 WHERE RAND() < 0.1 这样的条件进行近似抽样,然后调整比例以获取大约10000条数据。不过这些方法都有各自的优缺点,需要根据具体情况选择。 总结下来,回答的结构应该是: 1. 介绍使用 SQLAlchemy ORM 或 Core 的方法。 2. 提供示例代码,包括连接数据库、构建查询、获取结果。 3. 提醒性能问题,并给出可能的优化建议。 4. 指出不同方法的适用场景和限制。 需要确保代码正确,比如检查 func.rand() 是否正确对应 MySQL 的 RAND(),以及连接字符串是否正确。同时,要解释每个步骤的作用,让用户能够理解代码的含义。另外,可能需要提到事务和会话的管理,特别是在使用 ORM 时,是否需要提交或关闭会话等,不过在示例中可能简化处理。 最后,可能还需要检查是否有常见的错误,比如忘记导入 func,或者驱动未安装(如 pymysql),需要提醒用户安装必要的库。</think>使用 SQLAlchemy 从 MySQL随机获取 10000 条数据,可以通过以下方法实现。这里提供两种方式:**ORM(对象关系映射)**和 **Core(原始 SQL 表达式)**,并会解释性能注意事项。 -- ### 方法 1:使用 SQLAlchemy ORM ```python from sqlalchemy import create_engine, func from sqlalchemy.orm import sessionmaker from your_module import YourModel # 替换为你的模型类 # 创建数据库连接(替换为你的 MySQL 连接信息) engine = create_engine("mysql+pymysql://user:password@host:port/database") Session = sessionmaker(bind=engine) session = Session() # 使用 ORDER BY RAND() 随机排序,并取前 10000 条 random_data = session.query(YourModel)\ .order_by(func.rand())\ # MySQL 的 RAND() 函数 .limit(10000)\ .all() session.close() ``` --- ### 方法 2:使用 SQLAlchemy Core(原始 SQL) ```python from sqlalchemy import create_engine, text # 创建数据库连接 engine = create_engine("mysql+pymysql://user:password@host:port/database") # 直接执行 SQL 语句 with engine.connect() as connection: result = connection.execute( text("SELECT * FROM your_table ORDER BY RAND() LIMIT 10000") ) random_data = result.fetchall() ``` --- ### ⚠️ 性能注意事项 1. **`ORDER BY RAND()` 的局限性**: - 当表中数据量极大(如百万级)时,`ORDER BY RAND()` 会为每条数据生成随机值并排序,效率极低。 - **适用场景**:适合小规模数据或对性能不敏感的操作。 2. **优化建议**(针对大数据表): - **预计算随机列**:新增一列存储随机数(如 0-1 之间的值),查询时按该列排序。 - **分页随机法**(需连续主键): ```sql SELECT * FROM your_table WHERE id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM your_table))) LIMIT 10000; ``` - **应用层随机**:先查询所有符合条件的 ID,在代码中随机选择一批 ID,再通过 `WHERE IN` 查询具体数据。 --- ### 完整示例(ORM 优化版) ```python import random from sqlalchemy import create_engine, and_ from your_module import YourModel engine = create_engine("mysql+pymysql://user:password@host:port/database") # 假设主键是自增整数 max_id = session.query(func.max(YourModel.id)).scalar() selected_ids = random.sample(range(1, max_id + 1), 10000) # 分批查询避免 IN 语句过长 chunk_size = 1000 data = [] for i in range(0, len(selected_ids), chunk_size): chunk_ids = selected_ids[i:i + chunk_size] chunk = session.query(YourModel)\ .filter(YourModel.id.in_(chunk_ids))\ .all() data.extend(chunk) ``` --- ### 总结 - **小数据量**:直接用 `ORDER BY RAND() LIMIT 10000`。 - **大数据量**:优先使用主键随机或预计算随机列优化性能。 - 根据实际场景选择 ORM 或 Core 方式,前者适合模型化操作,后者适合直接控制 SQL。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值