本文將向各位介紹如何使用MySql5.x中的空間數據庫,並展現一下它高效的性能(前提是正確使用)。html
本文適合於對SQL和MYSQL熟悉的人員。mysql
步驟1:建立支持空間查詢的表sql
首先來講一下如何建立一個包含空間數據的名爲Points的表。數據庫
CREATE TABLE `points` (函數
`name` varchar(20) NOT NULL DEFAULT '',性能
`location` point NOT NULL,測試
`description` varchar(200) DEFAULT NULL,大數據
PRIMARY KEY (`name`),spa
SPATIAL KEY `sp_index` (`location`)orm
) ENGINE=MyISAM DEFAULT CHARSET=gbk;
這條DDL命令建立了一個名爲Points的表,包含一個name字段和一個類型爲point的字段location(所處位置)及descrption(描述)字段。
正如你所看到的,空間類型字段的使用跟Mysql中其餘類型同樣,建立時選擇相應的類型便可。
空間數據類型的基類是Geometry。
能夠在下面的文檔中找到全部Mysql支持的空間數據類型:
http://dev.mysql.com/doc/refman/4.1/en/spatial-extensions.html
步驟2:向空間數據表中插入數據
咱們來看一看想Points表中的插入數據是多麼的簡單:
INSERT INTO Points (name, location) VALUES ( 'point1' , GeomFromText( ' POINT(31.5 42.2) ' ) )
這是一個普通的SQL插入操做,只有函數GeomFromText()是咱們之前未見過的。這個函數接受一個字符串,而且返回一個幾何對象。有關該字符串的GIS標準格式詳見:
http://dev.mysql.com/doc/refman/4.1/en/gis-wkt-format.html
步驟3:從空間數據表中讀取數據
從Points表中讀取數據也是很是簡單的:
SELECT name, AsText(location) FROM Points;
以上語句的返回結果中location會被轉換成跟第二步中同樣的GIS標準字符串。實際上AsText函數僅僅是把數據庫內部存儲的幾何對象格式化成一個字符串而已。
下面一個函數也是很是有用的:
SELECT name, AsText(location) FROM Points WHERE X(location) < 10 and Y(location) > 12;
該Select語句返回一系列location的X()(經度)小於10而且Y()(經度)大於12的點集合。
步驟4:空間表的高級查詢
把指定的幾何對象轉變易讀的文本:
SELECT AsText(Envelope(GeomFromText('LineString(1 1,2 2)')));
返回指定幾何對象的大小:
SELECT GeometryType(GeomFromText('POINT(1 1)'));
返回指定幾何對象的類型:
SELECT GeometryType(GeomFromText('POINT(1 1)'));
查找指定矩形範圍內的點:
SET @bbox = 'POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))';
SELECT name, AsText(location) FROM Points WHERE Intersects( location, GeomFromText(@bbox) );
步驟5:查找圓形區域內的點
這一步介紹如何查詢圓形區域(一般用一箇中心點和半徑來表示)內的幾何對象。
您首先想到的語句多是:
SET @point = 'POINT(10 10)';
SET @radius = 20;
SELECT name, AsText(location) FROM Points WHERE Distance(location, GeomFromText(@point)) < @radius;
可是這條語句運行會出錯,由於Distance函數尚未實現。MySql空間擴展文檔說明中已經說明他們只實現了OpenGis標準的一部分。
一個替代的方式是使用intersect函數。
MySql空間擴展文檔中已經指明各類幾何對象可使用intersect函數來判斷幾何對象是否和一個矩形相交。
這樣在取得近似範圍後咱們能夠再使用距離估算來過濾出正確的結果。
SET @center = GeomFromText('POINT(10 10)');
SET @radius = 30;
SET @bbox = CONCAT('POLYGON((',
X(@center) - @radius, ' ', Y(@center) - @radius, ',',
X(@center) + @radius, ' ', Y(@center) - @radius, ',',
X(@center) + @radius, ' ', Y(@center) + @radius, ',',
X(@center) - @radius, ' ', Y(@center) + @radius, ',',
X(@center) - @radius, ' ', Y(@center) - @radius, '))'
);
[1]
SELECT name, AsText(location)
FROM Points
WHERE Intersects( location, GeomFromText(@bbox) )
AND SQRT(POW( ABS( X(location) - X(@center)), 2) + POW( ABS(Y(location) - Y(@center)), 2 )) < @radius; To Obtain a result ordered by distance from the center of the selection area:
[2]
SELECT name, AsText(location), SQRT(POW( ABS( X(location) - X(@center)), 2) + POW( ABS(Y(location) - Y(@center)), 2 )) AS distance
FROM Points
WHERE Intersects( location, GeomFromText(@bbox) )
AND SQRT(POW( ABS( X(location) - X(@center)), 2) + POW( ABS(Y(location) - Y(@center)), 2 )) < @radius
ORDER BY distance;
步驟6:測試性能
最後一步咱們來試試在大數據量的狀況下空間數據查詢的性能。
首先咱們新建一個存儲過程,指定一個隨機數值隨機產生記錄插入到Points表中。
CREATE PROCEDURE fill_points(
IN size INT(10)
)
BEGIN
DECLARE i DOUBLE(10,1) DEFAULT size;
DECLARE lon FLOAT(7,4);
DECLARE lat FLOAT(6,4);
DECLARE position VARCHAR(100);
-- Deleting all.
DELETE FROM Points;
WHILE i > 0 DO
SET lon = RAND() * 360 - 180;
SET lat = RAND() * 180 - 90;
SET position = CONCAT( 'POINT(', lon, ' ', lat, ')' );
INSERT INTO Points(name, location) VALUES ( CONCAT('name_', i), GeomFromText(position) );
SET i = i - 1;
END WHILE;
END
而後調用該存儲過程,參數指定一個較大的數字,例如咱們想產生一百萬條記錄:
CALL fill_points(1000000);
而後咱們執行查詢[1]和[2]
在我機器上(Intel Core Duo 2.0 GHz Laptop)的測試結果是:
圓形區域選擇(即周邊搜索)結果不排序[1]
43862 rows in set ~1.10 sec with 1.000.000 records
圓形區域選擇(即周邊搜索)結果排序[2]
43862 rows in set ~1.72 sec with 1.000.000 records
http://blog.sina.com.cn/s/blog_a48af8c001018q1p.html