最好的Spatial Database(空間資料庫)當然是Oracle家的,可惜沒用過。最好的開源的Spatial Database一般公認是PostGIS,以前用過一陣子,安裝特別麻煩,不過各種功能很齊全。前段時間嘗試了一下MySQL的spatial extensions,下面記錄了一些使用心得:
1. MySQL Spatial Extensions(後面簡稱MySQL Spatial)功能不夠完全。至少和PostGIS相比是這樣的,它只支援了openGIS(一個標準)的一個子集,包涵有限的幾種空間資料類型(比如Point,LineString,Polygon等),支援的函數也很少,比如,連計算兩個點的distance函數都沒有...
2. MySQL Spatial的安裝配置非常的簡單。其實,它根本不需要安裝。預設的MySQL配置就能夠使用這些空間資料類型。這和PostGIS很不一樣,PostGIS是需要在PostgreSQL上再安裝一個擴充包。
3. 不同的儲存引擎有差別。MyISAM和InnoDB都支援spatial extensions,但差別在於:如果使用MyISAM,可以建立spatial index,而InnoDB是不支援的。這點差別在某些情境下很關鍵,後面會再詳細說說spatial index。
4. POINT的使用。點是最基本也是最常用的一種空間資料類型。MySQL Spatial中用POINT表示點,比如,可以建立一個table:
CREATE TABLE address (
address CHAR(80) NOT NULL,
address_loc POINT NOT NULL,
PRIMARY KEY(address),
SPATIAL KEY(address_loc)
);
其中,address_loc就是一個point類型,說明address_loc是一個點。
插入一個點:
INSERT INTO address VALUES('Foobar street 12', GeomFromText('POINT(2671 2500)'));
讀取一個點:
select AsText(address_loc) from address …
一個比較麻煩的問題是,如何計算兩個POINT的距離?之前說過了,MySQL Spatial不提供distance這個函數。官方指南的做法是這樣的:
GLength(LineStringFromWKB(LineString(point1, point2)))
這條語句大概的意思是用兩個點產生一個LineString的類型,然後調用GLength得到line的長度。
這麼做,也對也不對。
對是因為它確實計算的是距離,但是,這種方法計算的是歐式空間的距離。或者簡單的說,它計算的是直線距離。如果兩個點是地理座標,比如point(116.34, 39.28),想計算地理位置的距離,那麼這樣做肯定就不對了。正確的做法應該是使用專門計算地理位置的公式。
5. MySQL Spatial Index的使用。使用這樣的語句:
ALTER TABLE address ADD SPATIAL INDEX(address_loc);
可以在空間資料類型上建立一個spatial index,這個功能只有MyISAM才支援。Index的本質實際上是一個R-TREE,這也是最常用來作為多維資料索引的資料結構。
那麼,該如何使用這個index?
舉例來說,假設需要尋找某個矩形地區內所有的點,一種方法是這樣:
select * from address where (X(address_loc) > 116.3952) AND (X(address_loc) < 116.4052) AND (Y(address_loc) > 39.8603) AND (Y(address_loc) < 39.8703);
假設我們已經在address_loc這個column上建立了spatial index,所以上述的查詢應該很快。不幸的是,這不是事實。上述的查詢會掃描table內的所有資料,挨個進行計算,建立的index完全不起作用。
正確的做法是,在查詢中使用一些內建的和spatial有關的函數,只有這些函數能夠有效利用到index。比如,正確的查詢應該是:
select AsText(address_loc) from address where MBRContains(GeomFromText(Polygon((115.3073 40.3821, 115.3173 40.3821, 115.3173 40.4021, 115.3073 40.4021, 115.3073 40.3821))),address_loc);
這裡用到了函數MBRContains,用於判斷一個point是否在指定的polygon內部。這個函數就能夠很好的使用之前建立的spatial index。可以做個實驗,比較之前兩個查詢的處理時間,你會發現,後者的速度要快很多。
總的來說,如果只需要做一些簡單的GIS或者LBS的應用,MySQL提供的spatial extensions能夠滿足。但如果需要的功能更複雜一些,MySQL spatial extensions提供的功能可能就不夠用了,需要在MySQL之上自己實現更多的邏輯,或者換成PostGIS。
Reference:
【1】官方文檔: http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html
【2】官方文檔: http://dev.mysql.com/tech-resources/articles/4.1/gis-with-mysql.html