検索

ホームページ  >  に質問  >  本文

mongodb - 百万数据aggregate group sum 统计超级耗时的问题,求解决方案

1、文档结构示例

{
    _id: xxxx,
    user: 'xiaoming',
    level: 5,
    from: 'iPhone',
    info: 'something wrong'
}

2、场景:user为'xiaoming'的文档有六七百万条

3、问题:怎么提升aggregate+group+sum速度

aggregate([
    {$match:{user: 'xiaoming', info:{$regex:'wrong'}}},
    {$group:{_id:null, count:{$sum:1}}}
])

用上面这个来统计xiaoming带有wrong的文档数量,结果

{"_id": null, "count": 2299999 }

耗时30s-40s。user、info、user+info三种索引都尝试过,速度都没有提升
baidu、google查到‘带条件计数慢无解’
怎么提升效率,10s以内能实现吗

PHPzPHPz2840日前1938

全員に返信(3)返信します

  • PHP中文网

    PHP中文网2017-05-02 09:22:16

    最初に説明することは、OLAP タイプの操作では期待値が高すぎてはいけないということです。結局のところ、IO だけで通常の OLTP 操作をはるかに超える大量のデータの操作であるため、OLTP 操作の速度と同時実行性を要求することは非現実的であり、意味がありません。しかし、それは最適化の余地がないという意味ではありません。
    まずはインデックスから始めましょう。インデックスを作成せずに 600 万の {user: "xiaoming"} を見つけるのにどれくらい時間がかかりますか?フルテーブルスキャン COLLSCAN で 700 万個のデータから 600 万個のデータを見つけることと、1 億個のデータから 600 万個のデータを見つけることは、明らかに 2 つの異なる概念です。インデックス IXSCAN がヒットした場合、その差ははるかに小さくなり、ほとんど無視できます。したがって、 {user: 1} インデックスが効果がないというのは間違いです。コレクション内のデータ量が少なすぎて違いが分からないだけかもしれません。ちなみに、時間は不正確であるため、効率に違いがあるかどうかを確認するには、実行時間ではなく実行計画を見る必要があることに注意してください。 {user: "xiaoming"}需要多少时间?全表扫描COLLSCAN从700w条数据中找出600w条,跟从1亿条数据中找出600w条显然是两个概念。命中索引IXSCAN,这个差异就会小很多,几乎可以忽略。所以你说{user: 1}这个索引没有作用是不对的,可能只是因为集合数据量太少看不出差异而已。顺便应该提一下看效率是否有差异应该看执行计划,不要看执行时间,时间是不准确的。
    在有user索引的前提下,结果仍然有600w条,剩下的部分是个regexregex无法命中索引,所以不管有没有对info的索引都没有意义。在找到600w条数据之后还有一个对600w数据的filter操作。唯一对这个操作可能有帮助的只有全文索引,但全文索引并不能完全替代正则,具体问题需要读一下文档。考虑全文索引可行的情况下,可以建立复合索引:

    db.coll.createIndex({
      user: 1,
      info: "text"
    });

    对应地查询应该改为:

    db.coll.aggregate([
      {$match:{user: 'xiaoming', $text: { $search: "wrong" }}},
      {$group:{_id:null, count:{$sum:1}}}
    ])

    关于复合全文索引的介绍参考这里,仍然是有些限制需要注意。这样优化之后预计在同样的硬件下能降到20s以内,跟你要的10s内还有一段距离。原因开头说了,对OLAP就不能期望这么高。如果你真有这方面的需求,就应该从源头入手,考虑:

    1. 每次info user インデックスの前提では、まだ 600 万件の結果があり、残りの部分は regex がインデックスにヒットできません。 info へのインデックスがあるかどうかは関係ありません。 600 万個のデータが見つかった後、600 万個のデータに対して filter 操作が行われます。この操作に役立つ唯一のものは フルテキスト インデックス ですが、フルテキスト インデックスは正規表現を完全に置き換えることはできません。特定の質問についてはドキュメントを読む必要があります。全文インデックス作成が可能であることを考慮すると、複合インデックスを確立できます:
      リーリー

      対応するクエリは次のように変更する必要があります:
    2. リーリー
    3. 複合全文インデックスの概要については、ここを参照してください。注意すべき制限がいくつかあります。この最適化後は、同じハードウェア下で時間を 20 秒未満に短縮できると予想されますが、これは希望する 10 秒にはまだ程遠いです。冒頭でも述べたように、OLAP にはそこまで大きな期待はできません。本当にこのニーズがある場合は、ソースから始めて次のことを検討する必要があります:

      <オル>

    4. info フィールドが更新または挿入されるたびにカウントします
    または🎜🎜 🎜🎜時々統計を完了し、統計結果をキャッシュし、クエリ中にユーザーに直接表示します🎜🎜 🎜

    返事
    0
  • 某草草

    某草草2017-05-02 09:22:16

    分かりませんが、2試合に分けた方が良いでしょうか? 。

    に似ている リーリー

    大切なのは規則的に時間を過ごすことだと思います。

    インデックスがある場合は、ユーザーをインデックスします。

    返事
    0
  • 给我你的怀抱

    给我你的怀抱2017-05-02 09:22:16

    リアルタイム要件は高くなく、定期的にカウントしてキャッシュすることができます

    返事
    0
  • キャンセル返事