10亿数据如何做到1ms内查询?

一个大小18G、整整有8亿条数据的文件如何做查询:


思路:(首先我们只会对数据进行查询,不会进行任何增、删、改的操作)
①首先受限于文件的大小,肯定不能全部加载到内存中去查询。于是想到用一个文件指针逐行遍历文件,如果查询到就break,时间复杂度O(N)。实测效果如图,要查询的字段大概在文件30%的位置,耗时60s,由此可推测平均查找时间为60×10÷3÷2=1分40秒。 

②如果文件是有序的,因为机械硬盘可以随机访问,那么就可以利用二分的思想实现快速查询。但原始文件并不总是有序的,所以实际上在查询前我们还要进行排序。但是对这么大的文件排序,明显不能全部加载到内存里直接排序,于是对于笔者电脑而言(8G内存),将18G文件分成8份2.25G的文件再排序是相对合理的。

我们先将原始文件均分成8份txt并导出,然后再依次将生成的每个文件加载到内存里再排序。最后我们依次将得到的8个有序文件导出,接下来就是归并的过程了。

考虑到只有8个文件,为简便起见,我们采用2路归并算法:先将8个有序文件两两合并得到4个有序文件,再将4个有序文件两两合并得到2个有序文件,最后再将这两个文件合并得到我们排序后的最终文件。

于是在一番折腾后,终于得到了一个16多G的文件。。。

接下来就是二分,实际最后的文件只有7亿多行(去重、去掉无效数据后)。由于qq号码最长为10位,而手机号长度为11位,所以加上空格分隔符一条数据也只需要22个字符。

为保险起见,统一每行为25个字符,多余部分截断不考虑。于是又在一番折腾后终于得到了最后的文件(17.6G)。

下图为处理过程中产生的所有文件↓


最后轮到我们的二分出场,通过seekg(27*row,ios::beg)可以让文件指针在O(1)的时间内移动到任何一行,而耗时却可以几乎不计,很容易就能算出至多需要log(700000000)+1≈31(次)就能查出任何一条数据。

图三为执行1万次查询所用的时间,可以看到平均查找时间只有0.0005593秒(0.56ms),远低于方法①的100秒。

至此查询功能全部完成,所有代码均已同步至github(可惜我是不会开放public权限的,哈哈哈)

下图为实际查询效果,查询程序find.exe只有仅仅35kb大小且运行内存占用极小(仅用0.3m内存空间)。

猜你喜欢

转载自blog.csdn.net/ik666/article/details/125794527
今日推荐