我有一个包含9列和1200万行的大表,如下所示:
col1 col2 col3 col4 col5 col6 col7 col8 col9
12.3 37.4 7771 -675 -23 23.8 78.8 -892 67.5
79.3 -6.3 6061 -555 -24 28.1 77.1 -889 32.6
55.6 -7.3 8888 -921 -56 78.3 22.3 -443 22.9
.... .... .... .... .... .... .... .... ....
目前,该表在我的硬盘中保存为TSV(制表符分隔矢量)格式,大小为432MB。我想将表填充到Redis中以便最有效地完成这种查询:给定每列的最小值和最大值,计算在给定范围内的行数,即
(min_col1 <= col1 <= max_col1) &&
(min_col2 <= col2 <= max_col2) &&
(min_col3 <= col3 <= max_col3) &&
(min_col4 <= col4 <= max_col4) &&
(min_col5 <= col5 <= max_col5) &&
(min_col6 <= col6 <= max_col6) &&
(min_col7 <= col7 <= max_col7) &&
(min_col8 <= col8 <= max_col8) &&
(min_col9 <= col9 <= max_col9)
所以我的问题是:
1)如何将表填充到Redis中?我应该使用什么样的键/值数据结构?哈希,列表,集合,排序集还是其他什么?
2)在填充表格后,给出9列的9分钟和最大值,如何编写查询以获得计数,即在9个范围内的行数?我能想到的一种方法是,首先找出每个X在1到9中满足(min_colX&lt; = colX&lt; = max_colX)的行,然后计算它们的交集。但我想这不是最有效的方式。我只想尽快检索计数。
顺便说一下,我尝试过MongoDB。使用mongoimport填充表是很简单的,但是完成我的查询需要10秒,这对于我的实时应用来说太慢而且不可接受。相比之下,Redis将数据保存在内存中,所以我希望Redis可以将查询时间缩短到1秒。
供我参考,这是我在MongoDB中所做的。
mongoimport -u my_username -p my_password -d my_db -c my_coll --type tsv --file my_table.tsv --headerline
use my_db
db.my_coll.ensureIndex({col1:1, col2:1, col3:1, col4:1, col5:1, col6:1, col7:1, col8:1, col9:1 }).
db.my_coll.count({ col1: {$gte: min_col1, $lte: max_col1), col2: {$gte: min_col2, $lte: max_col2}, col3: {$gte: min_col3, $lte: max_col3}, col4: {$gte: min_col4, $lte: max_col4}, col5: {$gte: min_col5, $lte: max_col5}, col6: {$gte: min_col6, $lte: max_col6}, col7: {$gte: min_col7, $lte: max_col7}, col8: {$gte: min_col8, $lte: max_col8}, col9: {$gte: min_col9, $lte: max_col9} }).
我使用explain()来确保实际使用Btree索引而不是表扫描。
我还尝试创建ram磁盘并将我的MongoDB数据库保存到ram磁盘中,它将查询时间从10s缩短到9s,远远不能满足我的实时应用程序。
mkdir ~/ram
chmod -R 755 ~/ram
mount -t tmpfs none ~/ram -o size=8192m
mongod --dbpath ~/ram --noprealloc --smallfiles
答案 0 :(得分:3)
NoSQL领域有(有点)新玩家:Tarantool
它内置了二级索引,并且对它们的范围查询提供了一些支持。现在,AFAIK,只能进行>=
次查询。
来自User Guide:
box.select_range(space_no,index_no,limit,key,...)
从key指定的偏移量开始,选择一系列元组。密钥可以是多部分。限制选择最多限制元组。如果未指定任何键,则从索引中的第一个键开始。
似乎这是这项工作的好工具。但是,它需要一些额外的工作(编写代码来上限这些查询)。
答案 1 :(得分:3)
使每个col
成为一个有序集,然后在每个键上使用ZRANGEBYSCORE
,并在应用程序中进行交集和计数。我使用phpredis并使用array_intersect
在内存中做了很多。
性能问题在ZADD
中,您将用它来创建有序集。
一旦你在Redis的内存中创建了所有已排序的集合,剩下的就非常快了。
ZADD col1 12.3 line1
ZADD col1 79.3 line2
ZADD col1 55.6 line3
ZADD col2 37.4 line1
ZADD col2 -6.3 line2
ZADD col2 -7.3 line3
$COL1 = $redis->zrangebyscore('col1', -10, 10);
$COL2 = $redis->zrangebyscore('col2', 2010, 2012);
$count = count(array_intersect($COL1, $COL2));
希望有所帮助。