我想从要扫描大量行的表中随机返回行顺序
尝试:
1)通过rand()限制1从表顺序中选择*
2)从表中的id中选择*(通过rand()限制1从表顺序中选择ID)
2快于1,但在具有大行的表上仍然太慢
更新: 查询用于实时应用程序。插入,选择和更新大约为10 /秒。因此,缓存将不是理想的解决方案。在这种情况下,所需的行数为1。但是,在快速查询且所需行数> 1的情况下,还要寻找一种通用解决方案。
答案 0 :(得分:0)
最快的方法是在mysql和limit中使用预处理语句
select @offset:=floor(rand()*total_rows_in_table);
PREPARE STMT FROM 'select id from table limit ?,1';
EXECUTE STMT USING @offset;
total_rows_in_table =表中的总行数。
与上面两个相比,它要快得多。
局限性:获取1行以上并不是真正随机的事情。
答案 1 :(得分:0)
在执行查询之前生成随机的一组ID(如果需要,您也可以很快获得MAX(id))。然后以id IN (your, list)
进行查询。这将使用索引仅查看您请求的ID,因此速度非常快。
限制:如果某些随机选择的ID不存在,查询将返回较少的结果,因此您需要循环执行这些操作,直到获得足够的结果为止。
答案 2 :(得分:0)
如果您可以在同一“调用”中运行两个查询,则可以执行类似的操作,可悲的是,这假设您的数据库中没有已删除的记录...如果它们在某个查询中不返回任何内容。
我测试了一些本地记录,而我能做的最快的就是...表示我在没有删除行的表上进行了测试。
while(true)
另一个解决方案来自修改此问题的答案,以及您自己的解决方案: Using variables as OFFSET in SELECT statments inside mysql's stored functions
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
class Program
{
// Set a `wood` variable for the class.
protected int wood { get; set; }
static void Main(string[] args)
{
Program program = new Program(); // Making use of non-static methods.
program.Handler();
}
public void Handler()
{
Console.WriteLine("Write \"gamble\" to hit the tree.");
string message = Console.ReadLine();
if (message == "gamble")
{
addWood(); // Call the non-static method.
}
}
public bool addWood()
{
this.wood = this.wood + 10;
Console.WriteLine("You now have {0} wood!", this.wood);
Handler(); // Call the Handler() method again for infinite loop.
return true;
}
}
}
答案 3 :(得分:0)
我想象一个有100万个条目的表。您想随机选择一行,因此您需要为每行生成一个随机数,即一百万个随机数,然后使用生成的最小数查找行。涉及两个任务:
然后访问记录。
如果您想要多于一行,则DBMS可以对所有记录进行排序,然后返回n条记录,但是希望它宁愿应用某些仅对n个最小数字进行检测的部分排序操作。还是要完成一些任务。
我想,没有彻底的方法来规避这一点。如果您想随机访问,这就是方法。
但是,如果您准备好接受随机性较低的结果,我建议您制作ID存储桶。想象一下ID桶000000-0999999、100000-1999999,...然后随机选择一个桶,并从中随机选择一行。好吧,诚然,这看起来不是很随意,使用这种存储桶只会得到旧的记录,也可能只会得到新的记录。但这说明了这项技术。
您不是使用值创建存储桶,而是使用模函数创建它们。 id % 1000
会给您1000个存储桶。第一个ID为xxx000,第二个ID为xxx001。这样可以解决新记录/旧记录的问题,并使存储桶平衡。由于ID仅仅是技术性的东西,因此绘制的ID看起来如此相似根本没有关系。即使打扰您,也不要赚1000桶,而是说997。
现在创建一个计算列:
alter table mytable add column bucket int generated always as (id % 997) stored;
添加索引:
create index idx on mytable(bucket);
并查询数据:
select *
from mytable
where bucket = floor(rand() * 998)
order by rand()
limit 10;
这里只有约0.1%的表格进入排序。因此,这应该相当快。但我想那只能用很大的桌子和大量的水桶来支付。
该技术的缺点:
上个月的链接:http://rextester.com/VDPIU7354
更新:我刚意识到,如果生成的列不是基于ID的取模,而是基于RAND
值,则存储桶实际上是随机的:
alter table mytable add column bucket int generated always as (floor(rand() * 1000)) stored;
但是MySQL抛出错误“生成的列'bucket'的表达包含不允许的函数”。这似乎没有意义,因为使用STORED
选项可以确定函数,但至少在版本5.7.12中不起作用。也许在某些更高版本中?