Dan Donaldson
Dan Donaldson

Reputation: 1293

Why is this postgresql query so slow?

I'm no database expert, but I have enough knowledge to get myself into trouble, as is the case here. This query

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

is extremely slow. The points table has fewer than 2000 records, but it takes about 8 seconds to execute. There are indexes on the latitude and longitude columns. Removing the clause concering the resource_type and user_id make no difference.

The latitude and longitude fields are both formatted as number(15,10) -- I need the precision for some calculations.

There are many, many other queries in this project where points are compared, but no execution time problems. What's going on?

Upvotes: 1

Views: 576

Answers (4)

J-16 SDiZ
J-16 SDiZ

Reputation: 26920

You need a rtree index and use the @ operator, normal index won't work.

R-Tree http://www.postgresql.org/docs/8.1/static/indexes-types.html

@ operator http://www.postgresql.org/docs/8.1/static/functions-geometry.html

Upvotes: 0

user347594
user347594

Reputation: 1296

Probably you are missing the joins. Joining the table would be something like this.

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

For better indexes on coordinates use Quadtree or R-Tree index implementation.

If you intentionally did not miss the joins, try a subquery like this.

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

Upvotes: 3

Charles
Charles

Reputation: 51421

You're joining three tables, p, a, and c, but you aren't specifying how to attach them together. What you're getting is a full Cartesian join between all of the rows in all of the tables that match the criteria, then everything in areas.

You probably want to attach something in points to something in areas. And something in contacts with ... well, I don't know what your schema looks like.

Try sticking an "EXPLAIN" at the beginning for information on what's happening.

Upvotes: 5

OMG Ponies
OMG Ponies

Reputation: 332731

Did you forget something from your actual query? It's missing ANSI-89 joins between the three tables, giving you a cartesian product but only pulling out the POINTS records.

Upvotes: 11

Related Questions