mongodb - 百万数据aggregate group sum 统计超级耗时的问题,求解决方案
PHPz
PHPz 2017-05-02 09:20:16
0
3
1899

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以内能实现吗

PHPz
PHPz

学习是最好的投资!

répondre à tous(3)
洪涛

La première chose à noter est que pour les opérations de type OLAP, les attentes ne doivent pas être trop élevées. Après tout, il s'agit d'une opération portant sur de grandes quantités de données. Les E/S à elles seules vont bien au-delà de l'opération OLTP habituelle, il est donc irréaliste et dénué de sens d'exiger la vitesse et la simultanéité des opérations OLTP. Mais cela ne veut pas dire qu’il n’y a aucune place à l’optimisation.
Commençons par l’index. Combien de temps faut-il pour trouver 6 millions {user: "xiaoming"} éléments sans index ? Analyse de table complèteCOLLSCANTrouver 6 millions de données à partir de 7 millions de données et trouver 6 millions de données à partir de 100 millions de données sont évidemment deux concepts différents. Hit index IXSCAN, cette différence sera bien moindre et presque négligeable. Vous avez donc tort de dire {user: 1} que cet index n'a aucun effet. C'est peut-être simplement parce que la quantité de données dans la collection est trop petite pour voir la différence. À propos, il convient de mentionner que pour voir s’il y a une différence d’efficacité, il faut examiner le plan d’exécution et non le temps d’exécution, car celui-ci est inexact.
Avec l'index user, il y a encore 6 millions de résultats, et la partie restante est regex ne peut pas atteindre l'index, cela n'a donc aucun sens qu'il y ait un index pour regex ou non. Après avoir trouvé 6 millions de données, il y a une autre info opération sur 6 millions de données. La seule chose qui peut être utile pour cette opération est filter, mais l'indexation en texte intégral ne peut pas remplacer complètement les expressions régulières. Vous devez lire la documentation pour des problèmes spécifiques. Si l'indexation en texte intégral est réalisable, un index composite peut être établi : 全文索引

db.coll.createIndex({
  user: 1,
  info: "text"
});
La requête correspondante doit être modifiée en :

db.coll.aggregate([
  {$match:{user: 'xiaoming', $text: { $search: "wrong" }}},
  {$group:{_id:null, count:{$sum:1}}}
])
Pour une introduction à l'index composite en texte intégral, veuillez vous référer ici. Certaines limitations doivent encore être notées. Après cette optimisation, il est prévu que le temps puisse être réduit à moins de 20 secondes sous le même matériel, ce qui est encore loin des 10 secondes souhaitées. Comme mentionné au début, nous ne pouvons pas avoir des attentes aussi élevées envers OLAP. Si vous avez vraiment ce besoin, vous devriez partir de la source et considérer :

  1. Comptez chaque fois que le champ

    est mis à jour ou inséré info ou

  2. Créez des statistiques complètes de temps en temps, mettez en cache les résultats statistiques et affichez-les directement à l'utilisateur lors de la requête

某草草

Je ne sais pas, mais serait-ce mieux si cela pouvait être divisé en deux matches ? .

Similaire à

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

La chose principale à mon avis, c'est de prendre du temps.
S'il existe un index, indexez l'utilisateur.

给我你的怀抱

L'exigence en temps réel n'est pas élevée et peut être comptée régulièrement et mise en cache

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal