8
votes

PostgreSQL: Comment optimiser ma base de données pour stocker et interroger un graphique énorme

Je couronne PostgreSQL 8.3 sur 1,83 GHz Intel Core Duo Mac Mini avec 1 Go de RAM et Mac OS X 10.5.8. J'ai enregistré un graphique énorme dans ma base de données PostgreSQL. Il se compose de 1,6 million de nœuds et de 30 millions de bords. Mon schéma de base de données est comme: xxx

Les données dans les bords de la table ressemble à xxx

donc il stocke pour chaque nœud avec ID x le Lien sortant vers Id Y.

L'heure de la recherche de tous les liens sortants est OK: xxx

Cependant, si je recherche les liens entrants vers un nœud, la base de données est plus plus 100 fois plus lent (bien que le nombre résultant de liaisons entrants ne soit que 5 à 10 fois plus élevé que le nombre de liaisons sortants): xxx

J'ai essayé de forcer les postgres à ne pas utiliser une analyse bitmap via xxx

mais la vitesse de la requête pour les liaisons entrantes n'a pas amélioré: xxx

i Augmentation de mes tampons partagés de 24 Mo à 512 Mo, mais cela n'a pas aidé. Donc, je me demande pourquoi mes requêtes pour les liens sortants et entrants montrent un comportement asymétrique? Quelque chose ne va pas avec mon choix d'index? Ou devrais-je mieux créer une troisième tableau contenant tous les liens entrants pour un nœud avec ID X? Mais ce serait tout à fait un gaspillage d'espace disque. Mais depuis que je suis nouveau dans des bases de données SQL, je manque quelque chose de base ici?


4 commentaires

Cela ne change probablement rien, mais votre première requête est 'Sélectionnez l'identifiant des bords où ID = 4620' au lieu de 'Sélectionnez le lien des bords où ID = 4620'. Avec la première requête, je m'attendrais à une réponse instantanée indépendamment de l'ensemble de données.


Avez-vous exécuté "Analyser"; ou "analysement sous vide"; sur votre base de données récemment?


Jiri, tu avais raison. La première requête avait une faute de frappe. Je l'ai corrigé maintenant. Mais cela ne change pas le problème.


à Etelerant: j'ai essayé "analyses sous vide" mais cela n'a pas aidé. Le problème se produit également sur une base de données fraîchement générée.


5 Réponses :


5
votes

Je suppose que c'est à cause d'une "densité" des enregistrements identiques sur le disque. Je pense que les enregistrements avec le même identifiant sont stockés dans dense (c'est-à-dire peu de blocs) et ceux qui ont le même lien sont stockés dans des clauses (c'est-à-dire distribué à un grand nombre de blocs). Si vous avez inséré des enregistrements dans l'ordre d'identité, cette situation peut être produite.

suppose que: 1. Il y a 10 000 enregistrements, 2. Ils sont stockés dans l'ordre tel que (ID, lien) = (1, 1), (1, 2), ..., (1, 100), (2, 1) ..., et 3. 50 enregistrements peuvent être stockés dans un bloc.

Dans l'hypothèse ci-dessus, le bloc n ° 1 ~ n ° 3 est constitué des enregistrements (1, 1) ~ (1, 50), (1, 51) ~ (1, 100) et (2, 1) ~ (2 , 50) respectivement.

Lorsque vous SELECT * à partir des bords où ID = 1 , seuls 2 blocs (n ° 1, n ° 2) doivent être chargés et numérisés. D'autre part, Sélectionnez * à partir des bords où link = 1 nécessite 50 blocs (n ° 1, n ° 3, n ° 5, ...), même si le nombre de lignes est identique.


0 commentaires

1
votes

Votre problème semble être lié à Disk-io. Postgres doit lire les tunples des correspondances d'index afin de voir si la ligne est visible ou non (ceci ne peut pas être effectué à partir d'un index car il ne contient pas les informations nécessaires).

L'analyse sous vide (ou simplement analysera) aidera si vous avez beaucoup de lignes supprimées et / ou de lignes mises à jour. Courez-le d'abord et voyez si vous obtenez des améliorations.

Cluster pourrait également aider. Basé sur vos exemples, je dirais utiliser Link_idx comme clé de cluster. "Bords de cluster utilisant link_idx". Cela pourrait dégrader les performances de vos requêtes d'identification (vos requêtes d'identification peuvent être rapides car elles sont déjà triées sur disque). N'oubliez pas de courir Analyser après le cluster.

Les étapes suivantes incluent les paramètres de mémoire de réglage précis, en ajoutant plus de mémoire ou en ajoutant un sous-système de disque plus rapide.


0 commentaires

3
votes

Je pense HABE a raison.

Vous pouvez vérifier cela en utilisant cluster link_idx sur les bords; Analyser les bords après avoir rempli la table. Maintenant, la deuxième requête doit être rapide et doit d'abord être lente.

Pour que les deux requêtes deviennent rapidement, vous devrez se désoloraliser en utilisant une deuxième table, comme vous l'avez proposé. N'oubliez pas de cluster et d'analyser cette deuxième table après avoir chargé vos données, tous les EGDES reliant à un nœud seront regroupés physiquement.

Si vous ne vous interrogez pas tout le temps et que vous ne voulez pas stocker et vous ne voulez pas stocker et Sauvegarde de cette seconde table, vous pouvez donc le créer temporairement avant de interroger: xxx

Vous n'avez pas à regrouper cette table temporaire, car elle sera physiquement commandée directement sur la création. Il n'a pas de sens pour une requête, mais peut aider plusieurs requêtes d'une rangée.


1 commentaires

Cluster a pris trop de temps sur ma table. J'ai donc résolu le problème de créer une table supplémentaire dans l'analogie à votre suggestion: Créer des bords de table2 comme SELECT ID, lien entre les bords Ordonnance par lien; Créer index link_idx sur les bords2 (lien); une requête comme Sélectionnez ID à partir d'EDGES2 où link = 4620; ne prend que quelques ms. Merci!




-2
votes

Avez-vous essayé de faire cela dans www.neo4j.org? Ceci est presque trivial dans une base de données graphique et devrait vous donner des performances sur votre usecase en ms-gamme.


0 commentaires