随机访问指定数量的数据,还有什么更好的方法吗?

时间:2018-11-10 02:32:47

标签: mysql

MySQL获取随机条形数据

场景

需要从数据库中随机提取指定数量的数据,但是这个问题出奇的麻烦。

假设有一个数据表

sql Create table topic (   Id int primary key not null   Comment 'number',   Content varchar(20) not null   Comment 'content' )   Comment 'topic table';

  

此处的topic表具有两个主要功能   -可以比较主键(int)   -总体主键有一个趋势(自我增加/减少)

解决方案1:直接使用order by rand()

您可以直接使用order by rand()获取随机数据,并且可以获取所有数据(顺序仍然是随机的)。

  1. 根据rand()的结果 >此步骤等效于将rand()函数生成的数据列添加到每个数据,然后对该列进行排序
  2. 限制查询数量

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;

解决方案2:在哪里获取中间随机值

由于order by rand()导致的不进行索引的排序非常耗时,因此我们可以尝试解决此问题。

以下解决方案是这样的

  1. 在最大值和最小值之间取一个随机值
  2. 确定id是否大于(或小于)此随机值
  3. 限制查询数量

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,否则其偏差会更大(不一定太大或太小)。

解决方案3:使用临时表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 | | -------------------------------------------- | ----------------- | ----------------- | ----------- | |可以随意得到所有|是的几乎不可能|可以 |速度慢非常快|更快 |需要类似的主键类型|没有是的没有 |受数据分布密度的影响|没有是的没有 |速度受表数据复杂性影响|很大|很小|小|

0 个答案:

没有答案