2010-06-08 4 views
1

Je ne suis pas expert en base de données, mais j'ai assez de connaissances pour me mettre dans le pétrin, comme c'est le cas ici. Cette requêtePourquoi cette requête postgresql est-elle si lente?

SELECT DISTINCT p.* 
    FROM points p, areas a, contacts c 
WHERE ( p.latitude > 43.6511659465 
     AND p.latitude < 43.6711659465 
     AND p.longitude > -79.4677941889 
     AND p.longitude < -79.4477941889) 
    AND p.resource_type = 'Contact' 
    AND c.user_id = 6 

est extrêmement lente. La table de points a moins de 2000 enregistrements, mais il faut environ 8 secondes pour l'exécuter. Il y a des index sur les colonnes de latitude et de longitude. La suppression de la clause concerant le type_ressource et l'id_utilisateur ne fait aucune différence.

Les champs de latitude et de longitude sont tous deux formatés en nombre (15,10) - J'ai besoin de la précision pour certains calculs.

Il y a beaucoup, beaucoup d'autres requêtes dans ce projet où les points sont comparés, mais aucun problème de temps d'exécution. Que se passe-t-il?

+0

S'il vous plaît poster un Explain. Distinct est souvent un problème de performance. Assurez-vous également que la latitude et la longitude sont indexées. –

Répondre

11

Avez-vous oublié quelque chose dans votre requête actuelle? Il manque des jointures ANSI-89 entre les trois tables, vous donnant un produit cartésien mais en retirant seulement les enregistrements POINTS.

+2

Non seulement cela mais 'AND c.user_id = 6' ne fait rien car aucun résultat de' contacts' n'est retourné. – VeeArr

+0

mais lorsque les comparaisons sont seulement entre les points et les valeurs numériques longues et lat il n'y a pas de changement de vitesse. Il n'y a pas de joint possible, non? –

+0

@ user315975: Je ne sais pas vos données, mais n'incluez pas les tables si elles ne servent absolument à rien. Encore besoin de savoir comment 'POINTS' et' CONTACTS' se rapportent ... –

5

Vous joignez trois tables, p, a et c, mais vous ne spécifiez pas comment les attacher ensemble. Ce que vous obtenez est une jointure cartésienne complète entre toutes les lignes dans toutes les tables qui correspondent aux critères, puis tout dans les zones.

Vous voudrez probablement joindre quelque chose en points à quelque chose dans les zones. Et quelque chose dans les contacts avec ... eh bien, je ne sais pas à quoi ressemble votre schéma.

Essayez de coller un "EXPLAIN" au début pour obtenir des informations sur ce qui se passe.

+0

En effet. Vous pouvez avoir seulement 2000 enregistrements en points, mais si vous avez 2000 dans les zones et 2000 dans les contacts aussi, vous générez 2000 * 2000 * 2000 = 8 milliards de lignes, puis en les triant de nouveau. – Cowan

3

Il est probable qu'il vous manque les jointures. Rejoindre la table serait quelque chose comme ça.

SELECT DISTINCT p.* 
    FROM points p 
    JOIN areas a p ON a.FkPoint = p.id 
    JOIN contacts c ON c.FkArea = a.id 
WHERE ( p.latitude > 43.6511659465 
     AND p.latitude < 43.6711659465 
     AND p.longitude > -79.4677941889 
     AND p.longitude < -79.4477941889) 
    AND p.resource_type = 'Contact' 
    AND c.user_id = 6 

Pour de meilleurs indices sur les coordonnées utilisent quadtree ou R-Tree mise en œuvre de l'index.

Si vous n'avez pas manqué intentionnellement les jointures, essayez une sous-requête comme celle-ci.

select DISTINCT thePoints.* 
( 
    SELECT DISTINCT p.* 
    FROM points p 
    WHERE ( p.latitude > 43.6511659465 
      AND p.latitude < 43.6711659465 
      AND p.longitude > -79.4677941889 
      AND p.longitude < -79.4477941889) 
    AND p.resource_type = 'Contact' 
) as thePoints 
, areas, contacts 
WHERE c.user_id = 6 
Questions connexes