空間索引 各資料庫空間索引使用報告

2022-01-29 23:16:42 字數 4233 閱讀 7152

索引我們都用過,它是一種特殊的儲存結構,就像圖書館裡書的分類存放策略或是現代化圖書館裡的圖書查詢系統,能幫助我們快速找到自己需要的書。 資料庫中,索引的儲存一般使用 b樹 或 b+樹 來實現,通過二分法來查詢法來快速定位到資料位置。

普通索引對於一維資料(key->data)是無往不利,可是面對空間資料(lon,lat -> data)就有些無能為力了,如果查詢(116.27636, 40.041285)附近的點:

如此下來,就要用到空間索引了。空間索引通過 四叉樹、r 樹等資料結構,還有 geohash 演算法將二維資料轉化為一維使用普通b樹索引 來實現,它們都能實現對空間範圍內的快速搜尋。

可是,今天的主題不在這裡,我們的首要目標是要解決問題,這些空間索引的實現改日專門寫文章來實現。本文來說一說現有的資料庫中對空間索引的支援情況,希望能幫助跟我一樣的 gis 小白進行技術選型。

組內準備切換 poi 資料的儲存資料庫,花了一周時間安裝配置各種資料庫來測試空間索引的效率,測試了 redis, mongo, postgresql, mysql 這幾個知名的支援空間索引的資料庫,技術選型基本完畢,可是中間踩過的坑和配置經驗不能丟,詳情如下:

redis,乙個功能強大、效率極高的快取資料庫(或許已經不僅僅是快取資料庫了),已經成為類似於關係儲存型資料庫在各個專案中不可或缺的元件了。首先考慮它是因為它的效率有保障,而且專案中幾乎必備,運維代價很低。redis 的 空間索引採用 geohash 原理,配合集合儲存,查詢效率接近 log(n)。

redis 3.0 以上版本支援空間索引,新專案不必考慮這些,而一般的老專案可能就需要公升級 redis 了,另外 php 中可能還要公升級 redis 的擴充套件,以支援 redis 的空間索引函式。

redis 的安裝配置這裡就不再多提了,這裡簡單地介紹一下 redis 的 geo 系列函式。

redis 確實效率高,使用方便,但有乙個無法克服的問題,即無法實現多條件查詢。僅僅查詢附近的點,redis 是無懈可擊,但是如果需求是查詢附近的飯店呢?或是需求查詢附近的 '萬達' 呢?

不是不可以實現:

mongodb 是老牌的支援空間索引的資料庫,作為乙個文件型資料庫,它在儲存日誌或靜態資料時效果不錯。 它提供兩種型別的空間索引:

2d 索引 和2dsphere 索引都是使用 geohash 演算法用 b+ 樹來實現。

mongo 建立空間索引的方法很簡單:db.collection.createindex( );

查詢語句類似(下面是查詢距目標點 3000公尺 內的地點):

db.poi.find(  ,

$maxdistance : 3000}}

} )

mongo 的使用需要注意如下:

mongo 的空間索引還是比較靈活的,geojson 物件有點、線、多邊形、多條線段、多點、多個多邊形。支援 包含、相交、臨近的查詢,同時它也解決了 redis 的多條件查詢問題。

但是測試發現,mongo 有以下問題:

參考:mongodb地理空間索引和查詢(geospatial indexes)

mongodb » geojson

postgresql 是乙個知名的關係型資料庫,構建在其上的空間物件擴充套件模組 postgis 使得其成為乙個真正的大型空間資料庫。它通過 r樹 或 gist 樹索引來實現共空間索引,查詢效率極高。同時它對分詞模糊查詢支援很好,也能解決以地點名查詢的需求。

postgis 是乙個開源程式,它為物件-關係型資料庫postgresql提供了儲存空間地理資料的支援,使 postgresql 成為了乙個空間資料庫,能夠進行空間資料管理、數量測量與幾何拓撲分析。postgis 實現了 open geospatial consortium 所提出的基本要素類(點、線、面、多點、多線、多面等)的 sql 實現參考。

postgresql 的使用,對比其他資料庫來說,較繁瑣。

要使用 postgresql 的空間索引,需要安裝 postgis,由於它依賴多而複雜,能使用 yum,apt-get,homebrew 等工具的優先使用;

資料庫完畢後使用 initdb 命令初始化乙個資料庫;

使用非root使用者postgres -d datadir開啟服務;

使用create extension postgis;安裝擴充套件;

使用create index idx_name on table using gist(field);

然後就可以建表建索引導資料了。

以下是乙個典型的查詢語句(查詢跟目標點 3000公尺 內的地點名稱和距離):

select id, name, st_astext(loc), 

st_distance(loc, st_geographyfromtext('srid=4326;point(118.08688 33.64843)')) as dist

from test where

st_dwithin(loc, st_geographyfromtext('srid=4326;point(118.08688 33.64843)'), 3000)

order by dist asc limit 200;

使用時還需要注意:

postgresql 對空間查詢的支援非常靈活,足以支援多種複雜的空間查詢,postgis 能計算不同投影座標系下的真實空間距離,且查詢效率極高,在大量資料時也不會像 mongo 一樣效能急劇下降。

同時它關係型資料庫的特性支援我們進行多條件查詢,最後它也可以使用zhparser擴充套件來進行中文分詞,以支援對地點名模糊查詢。

雖然它在存在著複雜索引時寫入較慢的問題,但對於儲存不常變動的地點資訊來說,是無關大礙的。

參考: pgsql · 功能分析 · postgis 在 o2o應用中的優勢

postgresql 全表 全欄位 模糊查詢的毫秒級高效實現

mysql 的重要性和強大不必多言,它的儲存引擎 myisam 很早就支援空間索引。而 innodb 則在5.7.4 labs版本中才新增對空間索引的支援。

它們都是通過 r 樹來實現空間索引。

mysql 中空間索引使用時要注意:

以下是乙個典型的空間查詢語句(查詢距目標點3km以內的點):

select id, st_distance_sphere(point(-73.951368, 40.716743), geom) as dist, tags, st_astext(loc)

from nodes

where st_contains( st_makeenvelope(

point((-73.951368+(3/111)), (40.716743+(3/111))),

point((-73.951368-(3/111)), (40.716743-(3/111)))

), loc )

order by dist limit 10

由於 innodb 的功能比 myisam 強大太多,且事務、行鎖、b+樹索引等功能的不可替代性,這裡不再討論 myisam。

mysql 的空間索引查詢效率不低。作為傳統的關係型資料庫,其多條件支援、分詞也都被很好地支援。

雖然對 innodb 的空間索引有信心,也略期待,可是對乙個長時間存在的系統來說,資料庫版本的公升級真正不是乙個簡單的事。

參考:mysql blog - mysql對gis空間資料的支援

我以 126萬 poi 資料進行了測試,查詢範圍 3km 內的點(最多取200條)。 系統資訊: macos10.12 (x86_64); 核心: 2 ghz intel core i5; 記憶體: 8 gb 1867 mhz lpddr3;

以下是各資料庫的對比情況:

資料庫耗時

區域查詢

多條件支援

分詞支援

運維複雜度

備註redis(3.2.8)

1-10ms

不支援不支援

不支援低

簡單但功能單一

mongo(3.4.4)

10-50ms

支援支援

不支援中

結果資料量大時效能下降明顯

postgresql(9.6.2)

3-8ms

支援支援支援中

資料寫入較慢

mysql(5.7.18 innodb)

8-15ms

支援支援支援低

版本公升級太困難

資料庫沒有哪個一定好,只要適合場景即可。

Mysql的索引空間重用 資料庫索引原理

先看個例子 在下面這個表t中,如果我執行 select from t where k between3and5,需要執行幾次樹的搜尋操作,會掃瞄多少行?mysql create table t id int primary key,k int not null default 0,s varchar...

資料庫索引使用

1 不宜建立索引的情形 1 經常插入,修改和刪除的表 2 資料量比較小的表,因為查詢優化器在搜尋索引時所花費的時間可能會大於遍歷全表的資料所需要的時間 2.適合建立索引的情形 1 為where子句中出現的列建立索引 2 建立組合索引 3 為group by子句中出現的列建立索引 3.聚集索引的設計原...

資料庫索引 索引失效

以下情況不走索引 select from student where name like xiaoyao select from student where not score 100 select from student where score 100 select from student w...