[英]Optimizing mysql query to select all points with in polygon using spatial indexes
首先,我承認我的空間功能經驗非常少。 我在MySQL中有一個包含20個字段的表和23549187個包含地理數據的記錄。 其中一個字段是“點”,它是點數據類型並且在其上具有空間索引。 我有一個查詢,選擇多邊形內的所有點,如下所示,
select * from `table_name` where ST_CONTAINS(ST_GEOMFROMTEXT('POLYGON((151.186 -23.497,151.207 -23.505,151.178 -23.496,151.174 -23.49800000000001,151.176 -23.496,151.179 -23.49500000000002,151.186 -23.497))'), `point`)
這很好用,因為多邊形很小。 但是,如果多邊形變得龐大,執行時間變得非常慢,最慢的查詢到現在為止已經運行了15分鍾。 添加指數確實有助於將其降低到15分鍾,否則將花費近一個小時。 我有什么可以做的,以進一步改進。 此查詢將由作為守護程序運行的PHP腳本運行,我擔心這種慢速查詢會導致MySQL服務器崩潰。
我們歡迎所有建議讓它變得更好。 謝謝。
編輯:
show create table;
CREATE TABLE `table_name` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`lat` float(12,6) DEFAULT NULL,
`long` float(12,6) DEFAULT NULL,
`point` point NOT NULL,
PRIMARY KEY (`id`),
KEY `lat` (`lat`,`long`),
SPATIAL KEY `sp_index` (`point`)
) ENGINE=MyISAM AUTO_INCREMENT=47222773 DEFAULT CHARSET=utf8mb4
我不應該在這里披露更多的字段,但過濾器贏了
解釋慢查詢的sql輸出:
+----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+ | 1 | SIMPLE | table_name | ALL | NULL | NULL | NULL | NULL | 23549187 | Using where | +----+-------------+------------+------+---------------+------+---------+------+----------+-------------+
用較小的多邊形解釋sql輸出以進行查詢,
+----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+ | 1 | SIMPLE | table_name | range | sp_index | sp_index | 34 | NULL | 1 | Using where | +----+-------------+------------+-------+---------------+----------+---------+------+------+-------------+
看起來最大的多邊形不使用索引。
MySQL使用R-Trees來索引空間數據。 與B-Tree索引一樣 ,這些索引最適合針對總數的一小部分的查詢。 隨着邊界多邊形變大,可能匹配的數量增加,並且在某些時候,優化器決定切換到全表掃描更有效。 這似乎是這里的情景,我看到三個選項:
首先,嘗試在查詢中添加LIMIT
。 通常,如果優化器在完整表掃描中得出的I / O搜索次數較少,則MySQL會忽略該索引。 但是,至少使用B-Tree索引,MySQL將使該邏輯短路並且在LIMIT
存在時始終執行B-Tree潛水。 我假設R-Tree有類似的短路。
其次,與第一個類似,嘗試強制MySQL使用索引 。 這指示MySQL表掃描比優化器決定的更昂貴。 理解優化器只有啟發式,並且不知道“昂貴”的東西是如何超出其內部統計數據的結論。 我們人類有直覺,有時 - 有時 - 知道更好。
select * force index (`sp_index`) from `table_name` where ST_CONTAINS(ST_GEOMFROMTEXT('POLYGON((151.186 -23.497,151.207 -23.505,151.178 -23.496,151.174 -23.49800000000001,151.176 -23.496,151.179 -23.49500000000002,151.186 -23.497))'), `point`)
最后,如果那些不起作用,那么你需要做的是將邊界多邊形分解成更小的多邊形。 例如,如果您的邊界多邊形是每邊500公里的正方形,則將其分成每邊250平方公里的4個方格,或每邊125平方公里,等等。然后UNION
所有這些組合在一起。 索引將用於每個索引,累積結果可能更快。 (注意:這是重要的UNION
在一起:MySQL不能在空間查詢應用多個范圍掃描)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.