À titre d'exemple simplifié, supposons que j'ai un tableau comme celui-ci:
seq | value
----+------
102 | 11954
211 | 43292
278 | 19222
499 | 3843
La table peut contenir des centaines de millions d'enregistrements, et je dois fréquemment effectuer des requêtes comme celle-ci:
SELECT sum(value) WHERE seq > $a and seq < $b
Même si elle seq
est indexée, une implémentation de base de données typique parcourra chaque ligne pour calculer la somme dans le meilleur des cas O(n)
, où n
est la taille de la plage.
Y a-t-il une base de données qui peut le faire efficacement, comme dans O(log(n))
la requête?
J'ai rencontré une structure de données appelée un arbre de segment comme décrit ici . Parfois également appelé arbre de plage ou arbre d'intervalle, bien que tous ces noms soient souvent décrits comme une variation légèrement différente de la structure des données.
Cependant, je n'ai rencontré aucune base de données qui implémente une telle structure de données. L'implémentation à partir de zéro est facile pour une structure en mémoire, mais devient délicate si elle doit être persistante ou trop grande pour tenir dans la mémoire. S'il existe un modèle efficace pour l'implémenter au-dessus d'une base de données existante, cela pourrait également aider.
Note latérale: Ce n'est pas un tableau à ajouter uniquement, donc une solution telle que conserver une somme cumulée ne fonctionnera pas dans ce cas.
Réponses:
Utilisation des index SQL Server ColumnStore
Eh bien, d'accord, un seul - un index CS en cluster.
Si vous voulez en savoir plus sur le matériel sur lequel j'ai fait cela, rendez-vous ici . Divulgation complète, j'ai écrit ce billet de blog sur le site Web de la société pour laquelle je travaille.
À l'épreuve!
Voici du code générique pour construire une assez grande table. Même avertissement que Evan, cela peut prendre un certain temps pour construire et indexer.
Eh bien, Evan gagne pour la simplicité, mais j'ai parlé de ce auparavant.
Voici la définition de l'index. La et dee et dah.
En regardant un décompte, chaque ID a une distribution assez uniforme:
Résultats:
...
Chaque identifiant ayant environ 5 005 005 lignes, nous pouvons examiner une assez petite plage d'identifiants pour obtenir une somme de 10 millions de lignes.
Résultat:
Profil de requête:
Pour le plaisir, une agrégation plus importante:
Résultats:
Profil de requête:
J'espère que cela t'aides!
la source
PostgreSQL avec un index BRIN
Ce n'est pas vrai. Au moins, aucune base de données décente ne fera cela. PostgreSQL prend en charge la création d' index BRIN sur ces types de tables. Les index BRIN sont super petits et peuvent tenir dans un bélier même sur des tables aussi grandes. Des centaines de millions de rangées ne sont rien.
Ici, 300 millions de lignes définies comme vous les avez commandées. Attention, sa création peut prendre un certain temps (durée: 336057.807 ms + 95121.809 ms pour l'index).
Et maintenant...
1,4 seconde pour agréger / additionner 5 889 135 lignes dans la plage donnée.
Bien que le tableau soit de 10 Go, l'indice BRIN est de 304 kB.
Même plus vite
Si ce n'est toujours pas assez rapide, vous pouvez mettre en cache les agrégats par 100k lignes.
Maintenant, vous n'aurez plus qu'à utiliser les
2(1e5-1)
lignes de saumure et d'agrégation plutôt que 300 millions ou autre.Matériel
Lenovo x230, i5-3230M, 16 Go de RAM, 1 To SSD Samsung 840.
la source
O(n)
, peut-êtreO(sqrt(n))
. Dépend de la façon dont vous définirez les intervalles à utiliser dans la matérialisation.