[postgis-users] Query performance issue
Michael Fuhr
mike at fuhr.org
Wed Oct 12 20:27:54 PDT 2005
On Wed, Oct 12, 2005 at 04:40:57PM -0400, Stephen Woodbridge wrote:
> Michael Fuhr wrote:
> >UPDATE streets SET prov = (
> > SELECT prov_ab
> > FROM province b
> > WHERE streets.the_geom && b.the_geom AND intersects(streets.the_geom,
> > b.the_geom)
> > ORDER BY prov_ab
> > LIMIT 1
> >);
>
> Ah, this is very interesting also. I had thought that it would be nice
> to store an array() of provinces if there were more than one, but I was
> not sure how to define the column and do that.
>
> The UPDATE example above does not seem correct, as it looks like it will
> update prov on ALL rows because there is not where in the UPDATE only in
> the sub-select. Is Postgres smart enough to apply the the where in the
> sub-select also to the UPDATE? The example in the doc page above implies
> this is not the case.
Are you referring to this example from the documentation?
UPDATE employees SET sales_count = sales_count + 1 WHERE id =
(SELECT sales_person FROM accounts WHERE name = 'Acme Corporation');
This example does something different: it uses a subselect to
restrict the set of rows being updated, whereas the example I posted
updates every row in the table with the value returned by a subselect
that's run once for each row. That is, my example essentially does
the following:
for every row in the table
execute a query with this row's column values
assign the result to a column in this row
end
Isn't that what you're trying to do? Update every row in the streets
table to have the correct province, as in the following example?
CREATE TABLE province (
prov_ab char(2) PRIMARY KEY
);
SELECT AddGeometryColumn('province', 'the_geom', -1, 'POLYGON', 2);
CREATE TABLE streets (
name text PRIMARY KEY,
prov char(2)
);
SELECT AddGeometryColumn('streets', 'the_geom', -1, 'LINESTRING', 2);
COPY province (prov_ab, the_geom) FROM stdin DELIMITER '|';
BC|POLYGON((0 0,20 0,20 50,0 50,0 0))
AB|POLYGON((20 0,40 0,40 50,20 50,20 0))
SK|POLYGON((40 0,60 0,60 50,40 50,40 0))
MB|POLYGON((60 0,80 0,80 50,60 50,60 0))
\.
COPY streets (name, the_geom) FROM stdin DELIMITER '|';
Street 1|LINESTRING(10 20,30 20)
Street 2|LINESTRING(65 10,75 10)
Street 3|LINESTRING(45 10,55 10)
Street 4|LINESTRING(25 10,35 10)
Street 5|LINESTRING(5 10,10 10)
\.
SELECT s.name, AsText(s.the_geom), p.prov_ab, AsText(p.the_geom)
FROM streets AS s, province AS p
WHERE s.the_geom && p.the_geom AND intersects(s.the_geom, p.the_geom)
ORDER BY s.name, p.prov_ab;
name | astext | prov_ab | astext
----------+-------------------------+---------+---------------------------------------
Street 1 | LINESTRING(10 20,30 20) | AB | POLYGON((20 0,40 0,40 50,20 50,20 0))
Street 1 | LINESTRING(10 20,30 20) | BC | POLYGON((0 0,20 0,20 50,0 50,0 0))
Street 2 | LINESTRING(65 10,75 10) | MB | POLYGON((60 0,80 0,80 50,60 50,60 0))
Street 3 | LINESTRING(45 10,55 10) | SK | POLYGON((40 0,60 0,60 50,40 50,40 0))
Street 4 | LINESTRING(25 10,35 10) | AB | POLYGON((20 0,40 0,40 50,20 50,20 0))
Street 5 | LINESTRING(5 10,10 10) | BC | POLYGON((0 0,20 0,20 50,0 50,0 0))
(6 rows)
UPDATE streets SET prov = (
SELECT prov_ab
FROM province AS p
WHERE streets.the_geom && p.the_geom
AND intersects(streets.the_geom, p.the_geom)
ORDER BY prov_ab
LIMIT 1
);
SELECT name, prov, AsText(the_geom) FROM streets ORDER BY name;
name | prov | astext
----------+------+-------------------------
Street 1 | AB | LINESTRING(10 20,30 20)
Street 2 | MB | LINESTRING(65 10,75 10)
Street 3 | SK | LINESTRING(45 10,55 10)
Street 4 | AB | LINESTRING(25 10,35 10)
Street 5 | BC | LINESTRING(5 10,10 10)
(5 rows)
Notice that Street 1 matches two provinces so the update picked the
first one alphabetically (ORDER BY prov_ab LIMIT 1); the other
streets have all been assigned the province in which they're located.
Is that what you're after?
I don't know how the subselect method will perform versus the FROM
method on a large data set, but performance aside it should work.
--
Michael Fuhr
More information about the postgis-users
mailing list