mongodb随机查询一条记录的正确方法!
关于从mongodb库中随机取出一条记录的方法的博文很多,其中都提到了下面三种方法:
1、skip过随机数量的记录。
DBCursor cursor = coll.find(query);
int rint = random.nextInt(cursor.count());
cursor.skip(rint);
DBObject word = null;
if(cursor.hasNext()){
word = cursor.next();
cursor.close();
}
很多人说不推荐这种做法,如果数据量不是那么巨大,10万个记录以内完全可以使用这种方法。
其实让我写存储引擎的话,我肯定把这个方法搞成最快的。只查询,又不排序。用作查询的条件建好索引后,至少和方法2一样快。通过索引进行物理skip很容易直接就定位到要找的数据了。
2、增加一个random数值字段。
var random=Math.random();
var result=db.user.findOne({"random":{"$lt":random}});
if(result==null){
result=db.user.findOne({"random":{"$gte":random}});
}
很多人说这是效率较高的一种可行方法,但是如果你信了,又不加验证,那真叫坑了爹了!下面我们就分析一下。
findOne的机制是取出查询结果的第一条。这有什么问题看出来了吗?
内部的查询结果是按random字段排序的吗?问题显然不是那么好回答吧!通过试验发现:如果不建立索引,查询的结果是按照存储顺序排的。也就是说不管查询条件是小于,还是大于等于,都会取到符合条件的最早入库的记录。这大大降低了随机性,有没有啊。如果建立索引,查询的结果是按照random由小到大排序的,此时如果用小于等于条件,始终取回来的是random值最小的值。这就没有随机性了,是不是呢。也就是说,如果random升序需要使用大于条件,如果降序需要使用小于条件。但是没有指定排序的时候内部怎么给排序,你敢肯定吗?如果不敢肯定,是不是就得指定排序方式。从底层来说,你指定的排序方式跟索引的物理存放顺序一致才能达到最高的效率。
3、增加一个random空间位置字段。
db.coll.ensureIndex({ random: '2d' }) result = db.coll.findOne({ random: { $near: [Math.random(), 0] } })
将random建立为多值字段,两值得就可以,建立索引的时候当地理位置使用。取值的时候随机生成一个坐标,然后取离这个点最近一个值。
很多人把这个方法也列在推荐方法中,但是真的是高效率的方法吗?这个方法比较麻烦,很多人应该都没验证,直接抄写到自己博客了。其实用脑袋想想,这个方法比第二个方法更不靠谱呢。可以自己思考一种算法——在一群坐标中找出离某个坐标最近的一个坐标。好难哦,坐标点哎,他们本身并没有一个大小关系,也就是说没有天然的顺序。那些牛逼的查找算法都是基于排序的(基于哈希的本质也是基于排序的)。
那么怎么办?方法一:对两个分量建立两个索引。然后以查询点为中心点构建一个较小的矩形区域,查询的时候就是两个分量的范围的与关系。如果没查到结果扩大矩形区域,如果查询的结果过多,缩小矩形区域,这里就可以用二分法了。然后在矩形区域内精确计算距离。方法二:空间点按照相互距离聚类,然后将类别中心存储起来,然后采用方法一找到一个最近的类别中心,然后再在这个内别中使用方法一。方法三:求出所有点的外接矩形,然后把区域等分成4块的方法构建4叉树索引。构建过程就是把某个区域分成四等分,再把其中一份分成4等分,直到每个区域的点数少于给定值。这样查询的时候每层确定一次范围。最后一层暴力计算距离。我是想不出来更牛B的方法了!
可见最近空间距离的计算不轻松啊!
mongodb随机查询一条记录的正确方法!的更多相关文章
- 【面经】面试官:如何以最高的效率从MySQL中随机查询一条记录?
写在前面 MySQL数据库在互联网行业使用的比较多,有些小伙伴可能会认为MySQL数据库比较小,存储不了很多的数据.其实,这些小伙伴是真的不了解MySQL.MySQL的小不是说使用MySQL存储的数据 ...
- mysql_oracle_随机查询几条记录
数据库的随机查询SQL 1. Oracle,随机查询20条 select * from ( select * from 表名 order by dbms_random.value ) where ...
- 随机提取N条记录[多种数据库方法]
随机提取10条记录的例子: Sql server: select top 10 * from 表 order by newid() Access: SELECT top 10 * FROM 表 ORD ...
- mongodb索引--1亿条记录的查询从55.7秒到毫秒级别<补充版>
从头开始,验证mongodb的索引的好处.(window7环境下) 下载mongodb服务器,并解压到d盘,并使用以下命令启动 mongod --dbpath D:\mongodb\data mong ...
- TODO:从数据库中随机抽取一条记录
TODO:从数据库中随机抽取一条记录 1.最直接,最粗暴的方法先计算记录的总数,然后选择一个从0到记录总数之间的随机数n,利用skip跳过n条记录,这是效率低下的的方法,首先的记录总数,在用skip会 ...
- mysql 随机选取一条记录
要从tablename表中随机提取一条记录,大家一般的写法就是:SELECT * FROM tablename ORDER BY RAND() LIMIT 1. 1 2 3 4 5 6 7 8 9 1 ...
- Oracle整合Mybatis实现list数据插入时,存在就更新,不存在就插入以及随机抽取一条记录
作者:故事我忘了¢个人微信公众号:程序猿的月光宝盒 目录 Oracle整合Mybatis实现list数据插入时,存在就更新,不存在就插入 entity 对应表中字段,如不对应,在xml中起别名 map ...
- 【转】oracle 中随机取一条记录的两种方法
oracle 中随机取一条记录的两种方法 V_COUNT INT:=0; V_NUM INT :=0; 1:TBL_MYTABLE 表中要有一个值连续且唯一的列FID BEGIN SELECT COU ...
- mysql 查询一条记录的下一条和上一条记录
如果ID是主键或者有索引,可以直接查找: 方法一: 查询上一条记录的SQL语句(如果有其他的查询条件记得加上other_conditions以免出现不必要的错误): select * from tab ...
随机推荐
- .net core webapi 文件上传在 Swagger 文档中的有好提示处理
前提: 需要nuget Swashbuckle.AspNetCore 我暂时用的是 4.01 最新版本: 描述:解决 .net core webapi 上传文件使用的是 IFormFile,在S ...
- IdentityServer4实现单点登录统一认证
什么是单点登录统一认证:假如某公司旗下有10个网站(比如各种管理网站:人事系统啊,财务系统啊,业绩系统啊等),我是该公司一管理员或者用户,按照传统网站模式是这样:我打开A网站 输入账号密码 然后进入到 ...
- android android遇到的错误
android遇到的错误 一.eclipse运行.生成.打包APK报错: 原因1: jdk版本太低,升级jdk 原因2: tools选择: android sdk build-tools 大于等于2 ...
- NPOI row.Cells[i] 的坑
我有A行B列的EXCEL表格: 获取一行数据: IRow row=sheet.GetRow(i); 正常是这样的 row.Cells.Count = B; 但由于会存在没有激活的单元格,导致 row. ...
- 个人常用Markdow语法代码备用
1.分隔线 -------------------------------- 2.OC代码 ``` Objective-C ``` 3.字体加粗 ##加粗## 4.标题样式 <h1> &l ...
- C语言字符串拼接
1.使用strcat进行字符串拼接 #include <stdio.h> #include <stdlib.h> #include <string.h> int m ...
- 玩转php缓存memcache
记录 一.本地安装 链接:https://www.cnblogs.com/jkko123/p/6294669.html 二.linux安装
- SDUT OJ 迷之好奇 (字典树 )
迷之好奇 Time Limit: 2000 ms Memory Limit: 65536 KiB Submit Statistic Problem Description FF得到了一个有n个数字的集 ...
- Unity3d 中 将远程 MySQL 数据库转换为本地 Sqlite
1.创建MySQL2Sqlite脚本mysql2sqlite.sh:(代码地址:https://gist.github.com/esperlu/943776) #!/bin/sh # Converts ...
- Exadata 18.1新特性--云平台存储节点升级
1.传统方式的存储节点升级流程: (1).将存储节点升级包下载到数据库服务器,通常是DB01上. (2).解压缩存储节点升级包. (3).用升级包中的patchmgr工具滚动或非滚动地升级每个存储节点 ...