2012-07-09 10 views
0

J'ai deux tables: urls (table avec pages indexées, hôte colonne indexée, 30 millions de lignes) hôtes (tableau avec des informations sur les hôtes, l'hôte est colonne indexée, 1mln lignes)Comment gérer les jointures entre des tables énormes dans PostgreSQL?

L'un des plus fréquents SELECT dans mon application est:

SELECT urls.* FROM urls 
JOIN hosts ON urls.host = hosts.host 
WHERE urls.projects_id = ? 
    AND hosts.is_spam IS NULL 
ORDER by urls.id DESC, LIMIT ? 

dans les projets qui ont plus de 100 000 lignes dans le tableau urls la requête exécute très lentement.

Étant donné que les tables ont grandi, l'exécution de la requête est plus lente et plus lente. J'ai beaucoup lu sur les bases de données NoSQL (comme MongoDB) qui sont conçues pour gérer de si grandes tables mais changer ma base de données de PgSQL en MongoDB est pour moi un gros problème. En ce moment je voudrais essayer d'optimiser la solution PgSQL. Avez-vous des conseils pour? Que devrais-je faire?

+7

100k lignes n'est vraiment pas "énorme" du tout. –

+3

quels index avez-vous? – HLGEM

+0

Veuillez exécuter 'explain analyze' sur un échantillon de votre requête et ajouter le résultat à votre question, ainsi que la liste des index que vous avez dans les tables' hosts' et 'urls'.100k lignes est certainement quelque chose que pg devrait être capable de gérer sans trop de problème à moins qu'il ne soit vraiment affamé de ressources. – Lepidosteus

Répondre

0

Ajouter un index sur la (ce qui importe avant tout dans le tableau hosts,) colonne hosts.host, et un indice composite sur urls.projects_id, urls.id, exécutez la déclaration ANALYZE de mettre à jour toutes les statistiques et observer les performances subsecond quel que soit le pourcentage de spam.

Un conseil légèrement différent s'appliquerait si presque tout est toujours du spam et si les "projets", quels qu'ils soient, sont peu nombreux et très gros chacun. Explication: la mise à jour des statistiques permet à l'optimiseur de reconnaître que les tables urls et hosts sont toutes deux assez volumineuses (nous ne vous avons pas montré le schéma, donc nous ne connaissons pas la taille de vos lignes). L'indice composite commençant par projects.id exclura la plus grande partie du contenu urls, et son deuxième composant alimentera immédiatement le reste de urls dans l'ordre désiré, donc il est fort probable qu'un balayage d'index de urls sera la base pour le plan de requête choisi par le planificateur. Il est alors essentiel d'avoir un index sur hosts.host pour rendre les recherches d'hôtes efficaces; la majorité de cette grande table ne sera jamais accessible du tout.


) est ici où nous supposons que le projects_id est raisonnablement sélectif (qu'il ne soit pas la même valeur tout au long de toute la table).

1

Cette requête doit être rapide en combinaison avec les indices fournis:

CREATE INDEX hosts_host_idx ON hosts (host) 
WHERE is_spam IS NULL; 

CREATE INDEX urls_projects_id_idx ON urls (projects_id, id DESC); 

SELECT * 
FROM urls u 
WHERE u.projects_id = ? 
AND EXISTS (
    SELECT 1 
    FROM hosts h USING (host) 
    WHERE h.is_spam IS NULL 
    ) 
ORDER BY urls.id DESC 
LIMIT ?; 

Les indices sont l'ingrédient le plus important. La syntaxe JOIN telle que vous l'avez peut être tout aussi rapide. Notez que le premier index est un partial index et le second un multicolumn index avec l'ordre DESC dans la deuxième colonne. Cela dépend beaucoup des spécificités de votre distribution de données, vous devrez tester (comme toujours) avec EXPLAIN ANALYZE pour connaître les performances et savoir si les index sont utilisés.

General advice about performance optimization s'applique également. Vous connaissez le refrain.

Questions connexes