Mysql

MySQL 8 不使用空間索引?

  • October 26, 2021

我有一個問題,無論我做什麼我都無法讓 MySQL 使用空間索引。

像下面這樣的查詢需要 5 秒!

有什麼方法可以強制它使用索引嗎?

WITH ranked_reports AS (
   SELECT
       station_id,
       raw_text,
       observation_time,
       RANK() OVER ( PARTITION BY station_id ORDER BY observation_time DESC ) order_rank 
   FROM
       METAR 
   WHERE
       ST_Distance_Sphere (
           geo_point,
       ST_GeomFromText ( 'POINT(51.85 -0.79)', 4326 )) <= 100 * 1609.34 
   ) SELECT
   * 
FROM
   ranked_reports 
WHERE order_rank =1

查詢說明

+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-----------------------------+
| id | select_type | table      | partitions | type | possible_keys | key         | key_len | ref   | rows   | filtered | Extra                       |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-----------------------------+
|  1 | PRIMARY     | <derived2> | NULL       | ref  | <auto_key0>   | <auto_key0> | 8       | const |     10 |   100.00 | NULL                        |
|  2 | DERIVED     | METAR      | NULL       | ALL  | NULL          | NULL        | NULL    | NULL  | 585814 |   100.00 | Using where; Using filesort |
+----+-------------+------------+------------+------+---------------+-------------+---------+-------+--------+----------+-----------------------------+

表結構

CREATE TABLE `METAR` (
 `station_id` varchar(5) NOT NULL,
 `station_iata` varchar(5) DEFAULT NULL,
 `observation_time` datetime NOT NULL,
 `latitude` float(255,2) DEFAULT NULL,
 `longitude` float(255,2) DEFAULT NULL,
 `raw_text` varchar(255) DEFAULT NULL,
 `temp_c` float(255,1) DEFAULT NULL,
 `dewpoint_c` float(255,1) DEFAULT NULL,
 `wind_dir_degrees` int(255) DEFAULT NULL,
 `wind_speed_kt` int(11) DEFAULT NULL,
 `wind_gust_kt` int(11) DEFAULT NULL,
 `visibility_statute_mi` float(255,2) DEFAULT NULL,
 `altim_in_hg` float(255,2) DEFAULT NULL,
 `altim_in_hPa` float(255,0) DEFAULT NULL,
 `sea_level_pressure_mb` float(255,0) DEFAULT NULL,
 `wx_string` varchar(255) DEFAULT NULL,
 `sky_condition` mediumtext,
 `flight_category` varchar(255) DEFAULT NULL,
 `three_hr_pressure_tendency_mb` float DEFAULT NULL,
 `maxT_c` float(255,0) DEFAULT NULL,
 `minT_c` float(255,0) DEFAULT NULL,
 `maxT24hr_c` float DEFAULT NULL,
 `minT24hr_c` float(255,0) DEFAULT NULL,
 `precip_in` float(255,0) DEFAULT NULL,
 `pcp3hr_in` float(255,0) DEFAULT NULL,
 `pcp6hr_in` float(255,0) DEFAULT NULL,
 `pcp24hr_in` float(255,0) DEFAULT NULL,
 `snow_in` float(255,0) DEFAULT NULL,
 `vert_vis_ft` int(255) DEFAULT NULL,
 `time_added` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
 `geo_point` point NOT NULL /*!80003 SRID 4326 */,
 PRIMARY KEY (`station_id`,`observation_time`),
 KEY `IDX_Station` (`station_id`) USING BTREE,
 KEY `IDX_Deletion` (`observation_time`) USING BTREE,
 KEY `IDX_IATA` (`station_iata`,`observation_time`) USING BTREE,
 SPATIAL KEY `IDX_Spatial` (`geo_point`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

您的查詢有

WHERE
   ST_Distance_Sphere (
       geo_point,
   ST_GeomFromText ( 'POINT(51.85 -0.79)', 4326 )) <= 100 * 1609.34 
)

在 MySQL 中,您必須使用MBR函式才能使用索引。

所以不要ST_Distance_Sphere改用,

MBRContains( ST_Buffer( ST_SRID(POINT(51.85 -0.79), 4326), 100 * 1609.34), geog )

您需要將 SRID 添加到列定義:

SRID 屬性使空間列 SRID 受限,這具有以下含義:

該列只能包含具有給定 SRID 的值。嘗試插入具有不同 SRID 的值會產生錯誤。

優化器可以在列上使用空間索引。請參閱第 8.3.3 節,“空間索引優化”。

沒有 SRID 屬性的空間列不受 SRID 限制,並接受具有任何 SRID 的值。但是,在修改列定義以包含 SRID 屬性之前,優化器不能對它們使用 SPATIAL 索引,這可能需要首先修改列內容,以便所有值都具有相同的 SRID。

引用自:https://dba.stackexchange.com/questions/260757