RAKSUL TechBlog

RAKSULグループのエンジニアが技術トピックを発信するブログです

MySQL 5.7 → 8.0 移行で直面した空間データの盲点と対策

はじめに

こんにちは。ラクスル Advent Calendar 2025 3 日目を担当する、ラクスル事業部 Web エンジニアの森田です。

現在ラクスルでは MySQL 5.7 を Aurora の延長サポート環境で稼働させているため、MySQL 8.0 への移行を検証しています。

その過程で、とあるクエリが MySQL 5.7 では問題なく稼働していたにもかかわらず、8.0 環境下で応答時間が大幅に悪化する事象が発生しました。今回はこの事象から得られた知見を共有します。

事象

私が開発しているエリアマーケティングチームでは、ポスティングや新聞折込といった印刷から配布までワンストップで提供するサービスを扱っています。

新聞折込サービスには、全国の新聞販売店の配布エリアをポリゴンとして DB に保持し、ユーザーが地図上で指定した円形エリアと重なる販売店を導出するロジックが存在します。

この交差判定ロジックで使用されているポリゴンを使った検索クエリの実行時間が、 3 秒前後から 12 秒前後に悪化しました。

本プロダクトでは、地図検索の応答速度が重要指標であるため、これを改善する必要がありました。

原因

SRID の違い

原因を調査したところ、MySQL 8.0 から SRID(Spatial Reference System Identifier)の扱いが変更されていると判明しました。

SRID とは、空間データがどの座標系で表現されているかを示す識別子です。例えば 4612: 日本測地系、0: 平面直交座標系を表します。

5.7 系では、以下の箇所において SRID=4612 を明示していました。

  • 検索クエリ内での SRID 指定

  • DB のカラム定義(GEOMETRY 型列)

  • 空間インデックスの定義

しかし実は、MySQL 5.7 では SRID=0 以外は実質無視され、列やインデックスの SRID に関係なく SRID=0 として扱われていました。

MySQL 5.7 doesn’t really support any other SRIDs — they are simply ignored, and SRID 0 is assumed. *1

MySQL 8.0 で SRID が正しく評価され、SRID=4612 の空間インデックスが適用されるようになった結果、クエリの計算コストが増加し、パフォーマンスが悪化しました。

影響を受けた関数

今回のユースケースでは SPATIAL INDEX が効くMBRIntersects 関数を使用して、最小外接長方形(MBR)でざっくり絞り込みを行います。円とポリゴンをそれぞれ長方形で近似して比較し、候補を大幅に絞り込むための処理です。

実際の使用イメージは以下のようになります。(販売店ポリゴンは非公開情報のため、Nano banana で生成した画像でお届けします。)

MBRIntersects関数の使用イメージ

ここで重要なのが、MBRIntersectsは SRID の指定だけでなく、クエリ内でのジオメトリの渡し方によってもパフォーマンスが変わる という点です。

挙動の比較

  • ① MySQL 5.7 / SRID 4612 を指定する場合

SRID が無視され、平面座標系として処理されます。

  • ② MySQL 8.0 / SRID 4612 を関数呼び出しで指定する場合
EXPLAIN SELECT *
FROM spatial_table
WHERE MBRIntersects(
    ST_GeomFromText('POLYGON((35.0 135.0,35.0 135.1,35.1 135.1,35.1 135.0,35.0 135.0))', 4612),
    geom_column
) = 1;

この場合、EXPLAIN の結果を見ると

key: NULL

となり、SPATIAL INDEX は認識されません。MySQL は WHERE 句のST_GeomFromText(...) を 関数呼び出しとして扱い、毎行評価される可能性がある値 と見なすためです。*2

  • ③ MySQL 8.0 / SRID 4612 を定数化して指定する場合
SET @search_area = ST_GeomFromText(
  'POLYGON((35.0 135.0,35.0 135.1,35.1 135.1,35.1 135.0,35.0 135.0))',
  4612
);
EXPLAIN SELECT *
FROM spatial_table
WHERE MBRIntersects(geom_column, @search_area);

この場合は EXPLAIN に key: index_geom_column が表示され、オプティマイザは 定数のジオメトリとして認識 して SPATIAL INDEX を参照できます。

ただし SRID 4612 の計算コストは高いため、クエリはまだ遅いです。

  • ④ MySQL 8.0 / SRID 0 を指定する場合

オプティマイザは平面座標系として扱うため、5.7 時代と同等のレスポンスになります。

この違いも踏まえて、SRID とジオメトリの渡し方によるパフォーマンス差をまとめると以下の通りになりました。

No. MySQL バージョン クエリ例 インデックス認識 パフォーマンス
5.7 ST_GeomFromText(..., 4612) を WHERE に直接使用 無効(SRID 無視) 3 秒程度
8.0 ST_GeomFromText(..., 4612) を WHERE に直接使用 無効 12 秒程度
8.0 定数化 + SRID 4612 有効 10 秒程度
8.0 SRID 0 を指定 無効 3 秒程度

解決方法

今回のユースケースでは、以下の理由から パフォーマンスを重視して ④ SRID=0 を採用し、旧 5.7 時代のレスポンスと同じ速度まで回復しました。

  1. 使用している円の最大検索半径が 20km 程度で、地球の曲率による誤差はほぼ無視できる

  2. 円形エリアを元々多角形に近似してから交差判定を行っており、元々精度を最重要視しているわけでない

まとめ

今回の検証で、空間データの扱いがバージョン間で大きく変わることは盲点でした。

今後も、地図や空間データを扱う機能のパフォーマンスを保ちながら、UX を改善していくために、このような細かい仕様変更にも注意していきたいと考えています。