LoginSignup
3
0

More than 3 years have passed since last update.

MySQL 8.0でSPATIAL INDEXが使用されない

Last updated at Posted at 2019-07-15

はじめに

(追記)解決記事書きました。
https://qiita.com/miyauchi/items/89ae1870c5f611b2558c

MySQLのGEOMETRY型の列に対して検索をかけようとしたところSPATIAL INDEXが使われなかったので検証してみました。

※この記事を全部書き終わったところで下記の記事を見つけたので(多分)解決しました。SRIDしないとINDEX使われないし、警告も出ないそうな。まじかよ。
https://qiita.com/qyen/items/bc4a7be812253c2be9f9
※せっかく書いたから投稿しておきます。SRID指定した記事は気力があったら別記事として書く。

環境について

MySQLの8.0.16を使用しました。

mysql> SELECT version();
+-----------+
| version() |
+-----------+
| 8.0.16    |
+-----------+
1 row in set (0.00 sec)

テーブルの定義とデータの準備

まずは、GEOMETRY型の列geomを一つだけ定義したtestというテーブルを作成しました。
geom列にはSPATIAL INDEXが張られています。

このgeom列に対して検索をかけ、INDEXが使用されることを期待します。

mysql> SHOW CREATE TABLE test;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                           |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| test  | CREATE TABLE `test` (
  `geom` geometry NOT NULL,
  SPATIAL KEY `sp_index` (`geom`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

testテーブルに対し、1レコードだけデータをINSERTしました。

mysql> SELECT ST_AsText(geom) FROM test;
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ST_AsText(geom)                                                                                                                                                                                    |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| POLYGON((43.08256990265745 141.3162472988521,43.056831004971265 141.3162472988521,43.056831004971265 141.35259659542191,43.08256990265745 141.35259659542191,43.08256990265745 141.3162472988521)) |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

INSERTしたデータはPOLYGONで、北海道あたりで四角形のポリゴンです。

INDEXが使われるのかどうか検証

このデータに対してSELECTをかけたときに、INDEXが使われるのでしょうか?

ST_Intersects関数の場合

上記のポリゴンに重なるどうか判定するSELECT文を実行してみました。重なりの判定にはST_Intersects関数を使用しています。

mysql> SELECT ST_AsText(geom) FROM test WHERE ST_Intersects(geom, ST_GeomFromText('POINT(43.06 141.34)', 4326));
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ST_AsText(geom)                                                                                                                                                                                    |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| POLYGON((43.08256990265745 141.3162472988521,43.056831004971265 141.3162472988521,43.056831004971265 141.35259659542191,43.08256990265745 141.35259659542191,43.08256990265745 141.3162472988521)) |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

上記SQLでSPATIAL INDEXが使われたかどうか確認するためにEXPLAIN文を使用します。

mysql> EXPLAIN SELECT ST_AsText(geom) FROM test WHERE ST_Intersects(geom, ST_GeomFromText('POINT(43.06 141.34)', 4326));
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | test  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

残念ながらpossible_keysがNULLとなっており、INDEXが使用されていないことがわかりました。

ST_Contains関数の場合

では、ST_Intersects関数と似たような関数であるST_Containsではどうでしょうか?

mysql> EXPLAIN SELECT ST_AsText(geom) FROM test WHERE ST_Contains(geom, ST_GeomFromText('POINT(43.06 141.34)', 4326));
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | test  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

こちらもはやりINDEXは使用されませんでした。

等価演算子の場合

もしかして、空間関数を使った場合にSPATIAL INDEXが使われないのでは?と思い単純な等価演算子(=)で検証してみました。

mysql>  EXPLAIN SELECT ST_AsText(geom) FROM test WHERE geom=ST_GeomFromText('POLYGON((43.08256990265745 141.3162472988521,43.056831004971265 141.3162472988521,43.056831004971265 141.35259659542191,43.08256990265745 141.35259659542191,43.08256990265745 141.3162472988521))', 4326);
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | test  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

あれ?やっぱりSPATIAL INDEXは使用されません。

こうなってくるとPOLYGONに対してのINDEXが使用されないのでは?と思えます。

POINTデータの場合

ではPOINTデータでならばSPATIAL INDEXは使用されるのでしょうか?
POINTデータをINSERTしてみます。

mysql> INSERT INTO test VALUES (ST_GeomFromText('POINT(43.06 141.34)', 4326));
Query OK, 1 row affected (0.01 sec)

mysql> SELECT ST_AsText(geom) FROM test;
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ST_AsText(geom)                                                                                                                                                                                    |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| POLYGON((43.08256990265745 141.3162472988521,43.056831004971265 141.3162472988521,43.056831004971265 141.35259659542191,43.08256990265745 141.35259659542191,43.08256990265745 141.3162472988521)) |
| POINT(43.06 141.34)                                                                                                                                                                                |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

POLYGONの時と同じように等価記号による条件で検索してみます。

mysql> EXPLAIN SELECT ST_AsText(geom) FROM test WHERE geom=ST_GeomFromText('POINT(43.06 141.34)', 4326);
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | test  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |    50.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

やっぱりSPATIAL INDEXは使われませんでした。。。

最後に

こうなってくると一体どういうケースでSPATIAL INDEXが使われるのか?のほうが気になります。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0