1

Our task is to find the properties within the location specified by a client. We have a MySQL table that contains the longitudes and latitudes of properties.

address longitude latitude

address 1 42.4001742 -71.1213472

address 2 42.4651592 -71.01366

So, logically, we can do a SQL search based on the client location

Select * from addresses where longitude between (client.location. longitude + 0.1) 
and (client.location. longitude - 0.1) and latitude between 
(client.location. latitude + 0.1) and (client.location. latitude - 0.1)

How effective is this search in case of many thousands properties? What is a possible way to optimize this search?

5
  • 5
    You need to show us the table and index definitions, as well as row counts for each of the tables. Maybe your tables are defined poorly. Maybe the indexes aren't created correctly. Maybe you don't have an index on that column you thought you did. Without seeing the table and index definitions, we can't tell. We need row counts because that can affect query planning. If you know how to do an EXPLAIN or get an execution plan, put the results in the question as well. If you have no indexes, visit use-the-index-luke.com. Commented May 6, 2021 at 13:11
  • 1
    This looks like a spatial query on geography which adds lot of edge cases and trigonometry, so most DB engines have specialized Spatial Types to determine if points on a map intersect. Unfortunately it's not ANSI standard, so each DB is different and you didn't mention which one you use. So here's a SQL Server Example. Your SQL can be optimized with indexes on all of the lat and long columns, but your query is still searching in a physical 7SqMi rectangle. Commented May 6, 2021 at 14:06
  • Have you tried >= and < and compare the timing? Commented May 7, 2021 at 8:38
  • Can you please tag the DB engine you're using? Commented May 7, 2021 at 14:09
  • We use MySQL for DB Commented May 9, 2021 at 11:52

1 Answer 1

3
+50

You will want this index (use a BTREE index).

CREATE INDEX latlon ON addresses (latitude, longitude);

Your query will do an index range scan on the latitude (the south-north direction) and then filter on the east-west direction. That is fairly efficient.

One degree of latitude (south-north) is 69 miles or 111.111 km (based on the Napoleonic definition of meter ... ten million of them from the equator to the pole).

The distance per degree of longitude (west-east) varies based on how far you are from the equator. The further you are from the equator the shorter the distance. In Somerville, Mass, USA, one longitude degree is about 51 miles. (You did tell us where you are by your example.)

So if you want a bounding box three miles in each direction centered around (42.4002 -71.1213) you need this filtering clause.

WHERE latitude  BETWEEN  42.4002 - (3.0/69.0) 
                    AND  42.4002 + (3.0/69.0)
  AND longitude BETWEEN -71.1213 - (3.0/(69.0 * COS(RADIANS(42.4002))))
                    AND -71.1213 + (3.0/(69.0 * COS(RADIANS(42.4002))))

If you want to give your box in km, use 111.111 in place of 69.0. If you want a differently sized box use a different number in place of 3.0.

That filter expression uses the index I mentioned just fine.

If all the locations in your table are spread out mostly in the east-west direction but not the north-south direction (for example, along the Massachusetts Turnpike) then switch the order of the two columns in the index to get better selectivity. But usually this doesn't matter.

CREATE INDEX lonlat ON addresses (longitude, latitude);

You may find it helpful to read this.

Pro tip it's best to give lat/lon examples in oceans or cornfields.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.