Whats the metric used in MYSQL Spatial? - mysql

I am trying to determine the metric system for MySQL Spatial 5.6.12.
For example, I have the following table that created to store point geometry for multiple records.
CREATE TABLE POINTS_DATA(
RECORD_ID INT(15),
STREET_ADDRESS VARCHAR(50),
CITY VARCHAR(50),
STATE VARCHAR(25),
ZIPCODE VARCHAR(11),
LOCATION_GEO_CODES_SDO POINT NOT NULL,
SPATIAL INDEX(LOCATION_GEO_CODES_SDO),
PRIMARY KEY(RECORD_ID)
) ENGINE=MyISAM;
After the table was created, I inserted some records into the table successfully.
Now I have constructed the following query to fetch all the records that are within one mile from a specified LAT/LONG. Here is the query I run for that:
SELECT RECORD_ID, STREET_ADDRESS, CITY, STATE, ZIPCODE
, GLength(LineStringFromWKB(LineString(LOCATION_GEO_CODES_SDO
, POINT(-85.123,39.113))) AS DISTANCE
FROM POINTS_DATA
HAVING DISTANCE < 1 ORDER BY DISTANCE;
After running this query, I do get some records, but the distance does not seem to be in Miles or meters. It’s some fractional value like 0.0123, 0.0145, etc…
I could not find any documentation on this anywhere in MySQL? Does anyone know what metric system is in use in MySQL? And if there is, how can I convert it into miles?
That means, if I need to run the query above to fetch all records within one mile, how do I reconstruct it?

MySQL Spatial uses the spatial reference system of the geometry for GLength. You haven't defined what (if any) SRID you are using for your data, but guessing from the values you provide, the SRID is the default one. As a result, the values you are getting are just the Cartesian distance between the two points, using degrees as units.
Since you're only calculating distance of a line, you could drop GLength and calculate the distance yourself using the Haversine formula. See MySQL Great Circle Distance (Haversine formula).

Related

Mysql: can a query be served by Btree and geospatial index?

We use mysql 5.7 to store geospatial data. A table contains 5 columns store_id (String), tenant_id (String), type (enum), status(enum), boundaries (Multipolygon). The boundaries column has only one polygon but the type was set as MultiPolygon.
Our query has
SELECT DISTINCT store_id
FROM ${boundariesTable}
WHERE tenant_id = '${tenantId}'
AND status = '${status}'
AND type <> 'Z'
AND ST_Contains(boundaries, GeomFromText(
'Point(${coords.lng} ${coords.lat})'))
This DB call is very slow when boundary data has circles with several geolocation points. Hence, we want to use a geospatial index for the boundaries key. Would we need to modify the above query to use a geospatial index for the boundaries column? If yes then how should we structure the query? Without other parameters like type and tenantId, the number of rows increases multifold. So I am apprehensive to remove all other constraints and retain only the ST_Contains part of the query.
Thank

MySQL index for only maximum and minimum values

I have a huge table with millions of rows which stores the values obtained from some weather stations. Every row contains the station that gathered the value, the metric (for example, temperature, humidity, noise level, etc.), the date and the value itself.
This is its structure:
station: int(8)
metric: int(8)
date: datetime
value: float
And these are the indices I've defined:
PRIMARY KEY: station+metric+date
KEY: metrica (for the foreign key)
Sometimes, I'm interested in retrieving the last time every station has sent some value. Then I use this query:
SELECT station, MAX(date)
FROM MyTable
GROUP BY station
This query is very slow, as it has to read the entire table. If I add an index for station+date, the query now can use it and it becomes very fast. But the table storage also increases a lot, and for me indexing all date values is not useful, given I'm only interested on the max value.
So my question is if it's possible to create an index that indexes some range, ideally to only keep track of the maximum value.
Not that I know. But you have alternative solutions.
In other databases I'd suggest a materialized view, but MySQL does not support materialized views (SO#3991912) so you have to create and manage your own aggregate table your self.
If your source table is not updated too frequently a CREATE TABLE last_observation AS SELECT station, MAX(date) AS date FROM observations GROUP BY station will do the work. Simply issue the statement before any relevant request.
If your server has enough resources, you can leave the table in MEMORY, to get superfast responses. In that case you need to name explicitly the columns CREATE TABLE last_observation (station VARCHAR(x), lastDate DATE) ENGINE=MEMORY AS SELECT station, MAX(date) AS lastDate FROM observations GROUP BY station. Of course this statement should issued routinely each time you open mysql.
If your table is updated frequently, you can manage the content with triggers on the source table (Full tutorial here).
An other solution, on a totally different path, is to use a column oriented database. We used Infobright a few years ago, which has an free community edition, and is totally transparent for you (just install it and use mysql as before).
INDEX(station, date)
will handle that query efficiently. Alternatively, you could rearrange the PRIMARY KEY to (station, date, metric).
If you also want the temp on that date, then you are into a more complex groupwise-max .

Trouble getting count of points inside polygon with PostGIS

I am trying to find points from one table that fall within polygons from another table. Both tables have a geom column, both are using SRID 4326 which I confirmed using SELECT ST_SRID(geom) FROM poursafe.ca_licenses LIMIT 1;
I didn't create the polygon table with an SRID which should have been 2229. So, I ran this to convert it to 4326 which may be part of the problem?
ALTER TABLE public.ca_la_la_areas_neighborhoods ALTER COLUMN geom TYPE geometry(MultiPolygon,4326)
USING ST_Transform(ST_SetSRID(geom,2229),4326);
Both tables have spatial indexes (but, I don't know enough about them to know if I'm supposed to be running the query using them as my target tables?)
The query I am using to get the count is this:
SELECT count(*)
FROM public.ca_la_la_areas_neighborhoods pol
JOIN poursafe.ca_licenses poi ON (ST_Within(poi.geom, pol.geom));
I've tried this and many other attempts and get nothing but zeros as the count or select results.
CREATE ca_la_la_areas_neighborhoods (
gid INTEGER,
comty_name VARCHAR (40),
cert VARCHAR (3),
shape_star VARCHAR,
shape_stle VARCHAR,
geom GEOM
);
CREATE ca_licenses (
id BIGINT,
license VARCHAR,
type VARCHAR,
master VARCHAR,
lat DOUBLE PRECISION,
lon DOUBLE PRECISION,
geom GEOM
);

MySQL 5.7 Geospatial Index, will points concentrate in one point cause performance matter

I have many images's information store in MySQL, most of image have geo location info but others don't.
Since MySQL geospatial index doesn't allow null geometry point, I have to insert some nonsense point to the table like POINT(1000 1000).
If all images that don't have geo location info are set to POINT(1000 1000) will cause any problem?
Or is there any better way to satisfy this need?
Geospatial index is not needed in such case. Faster and simpler way to do this is to use KEY (lon, lat) and SELECT * FROM the_table WHERE lon > a and lon < b and lat > c and lat < d;
POINT or GEOMETRY can be null in MySQL (using either InnoDB or MyISAM storage engine) However, when you are creating the table the columns must be declared as not null.
Simply do this:
CREATE TABLE images(filename TEXT, location POINT NOT NULL);
INSERT INTO images(filename, location) VALUES ('hello.png', NULL);
SELECT count(*) FROM images WHERE location IS NULL;

Don't allow reversed composite primary key in MySQL

I'm developing an application which needs to hold data about distances between two cities.
I have created a distance table in the Mysql database which holds the name of the two cities and the distance between them. I have made the two town columns a composite primary key.
I'd like the database to restrict the application from making duplicated reversed entries like shown on the screenshot to prevent having different distance values.
What would be the best solution to solve this problem?
You could create a stored procedure to insert into this table.
DELIMITER $$
CREATE PROCEDURE insert_distance(IN p_town1 varchar(50), IN p_town2 varchar(50), IN p_distance int)
BEGIN
INSERT INTO distance(town1, town2, distance)
SELECT LEAST(p_town1, p_town2), GREATEST(p_town1, p_town2), p_distance;
END $$
DELIMITER ;
Using only this procedure to insert you make sure, that an error is thrown, when the entry already exists. And you don't insert the towns accidently in the wrong order.
MariaDB, a MySQL fork, offers virtual columns. If you were using MariaDB, you could create such a virtual column and declare it to be unique.
But, you probably don't have MariaDB (yet). So it's going to be hard for you to implement the business rule that prevents duplicate entries. You certainly could use a lookup scheme that would systematically ignore the prohibited entries (in which town_2 < town_1).
SELECT town_1, town_2, distance
FROM distance
WHERE town_2 > town_1
will retrieve all the valid entries. This query will retrieve the distance between two towns furnished as query parameters even if the two town names are offered in the wrong order. (The monkey business with the JOIN allows each town name parameter to be presented only once to the query, even though it is used more than once.)
SELECT town_1, town_2, d.distance
FROM (
SELECT ? AS a, ? AS b
) cities
JOIN distance AS d ON
( town_1 = LEAST(a,b) AND town_2 = GREATEST(a,b))