3

次のように、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 つの範囲内にある行数を取得するためにクエリを作成する方法は? 私が考えることができる 1 つの方法は、最初に 1 から 9 までの各 X について (min_colX <= colX <= max_colX) を満たす行を見つけてから、それらの交点を計算することです。しかし、これは最も効率的な方法ではないと思います。できるだけ早くカウントを取得したいだけです。

ところで、MongoDB を試してみました。mongoimport を使用してテーブルにデータを入力するのは簡単ですが、クエリを完了するのに 10 秒かかります。これは遅すぎて、リアルタイム アプリケーションには受け入れられません。それに対し、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} }).

テーブル スキャンではなく Btree インデックスが実際に使用されていることを確認するために、explain() を使用しました。

また、RAM ディスクを作成して、MongoDB データベースを RAM ディスクに保存しようとしましたが、クエリ時間が 10 秒から 9 秒に短縮されました。

mkdir ~/ram
chmod -R 755 ~/ram
mount -t tmpfs none ~/ram -o size=8192m
mongod --dbpath ~/ram --noprealloc --smallfiles
4

2 に答える 2

3

それぞれcolをソートされたセットにZRANGEBYSCOREしてから、各キーで使用し、アプリケーションで交差とカウントを行います。私はphpredisを使用しており、array_intersect.

パフォーマンスの問題はZADD、ソート済みセットの作成に使用する にあります。

すべてのソート済みセットが Redis のメモリに作成されると、残りは非常に高速です。


ソート済みセットの作成 (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

PHP、範囲、交差、カウントの検索

$COL1 = $redis->zrangebyscore('col1', -10, 10);
$COL2 = $redis->zrangebyscore('col2', 2010, 2012);
$count = count(array_intersect($COL1, $COL2));

それが役立つことを願っています。

于 2012-06-11T00:18:02.837 に答える
3

NoSQL分野に(ちょっと)新しいプレーヤーがいます:Tarantool

セカンダリ インデックスが組み込まれており、それらに対する範囲クエリのサポートがいくつかあります。現在、知る限り、>=クエリを作成することしかできません。

ユーザーガイドから:

box.select_range(space_no, index_no, limit, key, ...)

キーで指定されたオフセットから始まるタプルの範囲を選択します。キーはマルチパートにすることができます。最大 limit タプルで選択を制限します。キーが指定されていない場合は、インデックスの最初のキーから開始します。

これは、この仕事に適したツールのようです。ただし、少し余分な作業が必要です (これらのクエリの上限を設定するコードを記述します)。

于 2012-06-10T09:04:51.823 に答える