需要从数据库中随机提取指定数量的数据,但是这个问题出奇的麻烦。
假设有一个数据表
sql
Create table topic (
Id int primary key not null
Comment 'number',
Content varchar(20) not null
Comment 'content'
)
Comment 'topic table';
此处的
topic
表具有两个主要功能 -可以比较主键(int
) -总体主键有一个趋势(自我增加/减少)
order by rand()
您可以直接使用order by rand()
获取随机数据,并且可以获取所有数据(顺序仍然是随机的)。
rand()
的结果
>此步骤等效于将rand()
函数生成的数据列添加到每个数据,然后对该列进行排序 sql
Select *
From topic
Order by rand()
Limit 50000;
但是缺点很明显,速度是一个问题,因为rand()的数据没有索引,因此会导致排序速度很慢。
从10w数据中随机提取5w数据,这通常需要 6 s 378 ms ,但这一次确实太长了。
实际上,order by rand()
看起来很奇怪,实际上等同于:
sql
Select *
From
Select
Topic.*,
Rand() as order_column
From topic
) as temp
Order by order_column
Limit 50000;
由于order by rand()
导致的不进行索引的排序非常耗时,因此我们可以尝试解决此问题。
以下解决方案是这样的
sql
Select *
From topic
Where id >= ((select max(id)
From topic)
- (select min(id)
From topic))
* rand()
+ (select min(id)
From topic)
Limit 50000;
此方法非常快(150毫秒),但是受数据密度的影响。如果数据不是平均值,则数据查询的总数将受到限制。
所以,这是该方法的缺陷
获取的数据受分布密度的影响
例如,数据分布如下
1,100002,100003,100004...199999,200000
然后使用上面的代码将只获得少量数据(大约2.5w左右)。但是,如果稍微更改符号,将>=
更改为<=
,则可获得的平均数量将大大增加(约7.5w)。
此处的代码格式有误,我无法解决。 。
选择* 来自主题 #注意:此处的符号已被修改。 其中id> =((选择max(id) 来自主题) -(选择min(id) 来自主题)) * rand() +(选择min(id) 来自主题) 限制50000;
每条数据的概率不完全相同
尽管获得的所有数据都是随机的,但是每种数据的概率都不相同。例如,当<=
时,总是会出现第一个现象。原因是因为第一个**的概率太大,因为查询数据表时的数据检索规则是从第一个开始的!即使将其修改为>=
,获得的第一条数据通常也太小。
使用>=
的结果
-前面的数据越多,获取数据的可能性越低
-但是即使可能性很小,也总是有机会出现在顶部,因此第一个通常很小
-当数据密度太大时,获得的数量将非常小
密度趋于平均,获得的最大随机数据数的平均值更接近1/2
,否则其偏差会更大(不一定太大或太小)。
temporary
解决方案2着重避免在不建立索引的情况下使用rand()
进行排序,但在这里考虑另一种解决方案,在建立索引后使用添加的rand()
进行排序。创建一个临时表,该表仅包含需要排序的主键id
和索引列randomId
,然后在排序完成后获取乱序数据。
sql
Drop temporary table if exists temp_topic;
Create temporary table temp_topic (
Id bigint primary key not null,
randomId double not null,
Index (randomId)
)
As
Select
Id,
Rand() as randomId
From topic;
Select t.*
From topic t
Join (
Select id
From
Select id
From temp_topic
Order by randomId
) as temp
Limit 50000
) as temp
On t.id = temp.id;
此方法的查询速度不是很快(与第二个相比为878毫秒),它仍然与数据量成正比(因为要复制数据)。但是对于第一个,它也是真正的随机获取。
这是一篇不错的英文文章,它分析了随机访问数据:http://jan.kneschke.de/projects/mysql/order-by-rand/,其中有些在这里无效,为什么未知。 。
|差异| order by rand()
| where
| temporary
|
| -------------------------------------------- | ----------------- | ----------------- | ----------- |
|可以随意得到所有|是的几乎不可能|可以
|速度慢非常快|更快
|需要类似的主键类型|没有是的没有
|受数据分布密度的影响|没有是的没有
|速度受表数据复杂性影响|很大|很小|小|