mcpField
M
mariadb-query-optimization

mariadb-query-optimization

github.com/mariadbデータ・データベース17281 回インストール2 週間前に更新
リポジトリ

mariadb-query-optimization について

開発者やデータベース運用者向けに、MariaDB のクエリ性能を診断・改善するリファレンススキルです。監視、実行計画、インデックス、ページネーション、オプティマイザー統計を、MariaDB 固有の構文やバージョン差とともに扱います。

主な機能

  1. 01Performance Schema による監視の指針
  2. 02EXPLAIN と ANALYZE による計画診断
  3. 03インデックス選択とカバリングインデックス
  4. 04カーソル方式のページネーション
  5. 05ヒストグラムとオプティマイザー設定の指針

活用シーン

  1. 01本番環境の遅いクエリの調査
  2. 02クエリパターンに応じたインデックス選択
  3. 03深い OFFSET ページネーションの置き換え
  4. 04大量データ変更後の統計情報更新

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mariadb/skills --skill mariadb-query-optimization

インストール後、Claude Code で/mariadb-query-optimizationを入力して読み込まれたか確認します。

詳細

MariaDB クエリ最適化

最終更新日:2026-06-05

必要条件: ANALYZE とヒストグラムには MariaDB 10.1 以降が必要です。11.8 LTS(2025 年 5 月 GA)までのオプティマイザーの改善を、以下のベースラインとしています。

デフォルトの前提: ユーザーが別のバージョンを指定しない限り、MariaDB 11.8 LTS を前提とします。関連する場合は 12.x と記された機能も(アップグレードの選択肢としても)提案できますが、必ず最低バージョンを明記し、11.8 で利用可能な機能として提示しないでください。

LLM が誤りやすいこと

パターン代わりに行うこと
SELECT * FROM table LIMIT 10 OFFSET 50000カーソルベースのページネーションを使用します。OFFSET はスキップするすべての行をスキャンします
「インデックス付きの列に関数を使うとインデックスが無効になる」という一律のルールMariaDB 11.1+/11.3+ では、多くのケースで古い情報です。大文字と小文字を区別しない列の YEAR(col) = const と UPPER(col) = const は、現在ではインデックスを使用できる場合があります。以下のインデックス付きの列に対する関数を参照してください
カーディナリティの低い列(ブール値、2~3 種類の値を持つステータス)にインデックスを追加するオプティマイザーは選択性の低いインデックスをスキップし、代わりにテーブルスキャンを行います
大量の行を挿入した後に ANALYZE TABLE を実行しないヒストグラム統計が古くなり、オプティマイザーが適切でない実行計画を選ぶようになります
WHERE b = 1 AND c = 2 で複合インデックス (a, b, c) を使用する左端のプレフィックスルールにより、a がスキップされるため、このインデックスは使用されません
JOIN を含むクエリで SELECT * を使う必要な列だけを指定します。これにより、意図せずカバリングインデックスが使えなくなるのを防げます
インデックスを無効にするために ALTER TABLE t ALTER INDEX idx INVISIBLE を使うこれは MySQL の構文です。MariaDB では IGNORED を使います。以下の無視されるインデックス(INVISIBLE ではない)を参照してください
遅いサーバーで、すぐに EXPLAIN を実行したりインデックスを追加したりするまず、Performance Schema を起動時に有効にします。デフォルトではオフで、実行時には有効にできません
モニタリングを有効にするために SET GLOBAL performance_schema = ON を使うPerformance Schema を使うには、my.cnf に performance_schema=ON を設定し、サーバーを再起動する必要があります

Performance Schema(最初に有効化)

EXPLAIN の実行、インデックスの追加、クエリの書き換えを行う前に、サーバーがクエリの動作を観測できる状態か確認してください。MariaDB の Performance Schema は組み込みのモニタリングレイヤーです(10.5 以降では、performance_schema データベースに約 80 個のテーブルがあります)。

状態を確認します:

SHOW VARIABLES LIKE 'performance_schema';

重要: Performance Schema はデフォルトで無効で、実行時には有効にできません。OFF の場合は、my.cnf に設定を追加して再起動してください。

[mysqld]
performance_schema=ON

再起動後、必要なコンシューマーとインストゥルメントを有効にします。本番環境で無条件にすべてを有効にするのではなく、WHERE NAME LIKE '...' で対象を絞ってください。概要についてはドキュメントを参照してください。

UPDATE performance_schema.setup_consumers SET ENABLED = 'YES';
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES';

performance_schema(待機、ステージ、ステートメント、および関連するサマリーテーブル)を使って、時間がどこに費やされているかを確認します。その後、以下の EXPLAIN と ANALYZE を使って、オプティマイザーがその実行計画を選んだ理由を調べます。10.7.1 以降では、列のコメントを参考に各テーブルの内容を解釈できます。

SELECT column_name, column_comment
  FROM information_schema.columns
 WHERE table_schema = 'performance_schema' AND table_name = 'events_statements_summary_by_digest';

EXPLAIN の読み方

本番環境の遅延を診断する際に Performance Schema を利用できる場合は、EXPLAIN を実行してオプティマイザーの実行計画を確認します。

EXPLAIN SELECT * FROM orders WHERE customer_id = 42 ORDER BY created_at DESC LIMIT 10;

出力で注意すべき点:

フィールド注意すべき値意味
typeALL全テーブルスキャンです。インデックスがないか、使用されていません。
keyNULLインデックスが存在するのに使用されていません。列に対する関数や型の不一致がないか確認してください。
rows非常に大きい数値オプティマイザーは、多数の行をスキャンすると推定しています。
ExtraUsing filesortインデックスでカバーされない高コストなソートです。
ExtraUsing temporary一時テーブルが作成されています。多くの場合、GROUP BY または DISTINCT が原因です。
ExtraUsing index✅ 良好です。カバリングインデックスが使われており、テーブルの行にアクセスする必要はありません。

ANALYZE 文(MariaDB 10.1 以降)はクエリを実際に実行し、推定値と実際の行数を表示するため、EXPLAIN だけの場合より信頼性が高くなります。注意:MariaDB では EXPLAIN ANALYZE ではなく、ANALYZE を使用します。

ANALYZE SELECT * FROM orders WHERE customer_id = 42;

オプティマイザートレースでは、オプティマイザーの判断プロセス全体を確認できます。MariaDB 12.1 以降では、トレースにテーブルとビューの定義全体を含められます(システム変数 optimizer_record_context)。13.0 以降では、カーディナリティ推定に使用された統計情報(ヒストグラム、インデックス統計)も含まれるようになりました。これらを併用すると、予想外の rows 推定値の診断に役立ちます。

SET optimizer_trace = 'enabled=on';
SELECT * FROM orders WHERE customer_id = 42;
SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE\G
SET optimizer_trace = 'enabled=off';

インデックスのルール

最左プレフィックスルール

複合インデックス (a, b, c) では、MariaDB は次のように使用できます。

  • WHERE a = 1 ✅
  • WHERE a = 1 AND b = 2 ✅
  • WHERE a = 1 AND b = 2 AND c = 3 ✅
  • WHERE b = 2 ✗ — a をスキップするため、インデックスは使用されません。
  • WHERE a = 1 AND c = 3 — a の部分だけが使用されます。

選択性の高い等価条件を先に、範囲条件を最後に配置します。

-- Query: WHERE status = 'active' AND created_at > '2025-01-01' ORDER BY created_at
INDEX (status, created_at)  -- ✅ equality first, range last
INDEX (created_at, status)  -- ✗ range first breaks the prefix for status
カバリングインデックス

カバリングインデックスには、クエリに必要なすべての列が含まれているため、テーブルの行にアクセスする必要はありません(EXPLAIN では Using index と表示されます)。

-- Query fetches id, status, created_at for a customer
-- Covering index includes all three:
CREATE INDEX idx_customer_cover ON orders (customer_id, status, created_at);
-- Now EXPLAIN shows: Extra = Using index
インデックスを追加しない場合
  • カーディナリティの低い列:active/inactive の値を持つ status 列が行の 50% に該当する場合、オプティマイザーはテーブルスキャンを優先します。インデックスは、選択性の高い他の列と組み合わせた場合にのみ有用です。
  • 小さなテーブル(数千行未満):非常に小さなテーブルでは、インデックス検索より全件スキャンのほうが高速です。
  • 書き込み頻度の高い列:インデックスは INSERT、UPDATE、DELETE を遅くします。ほとんどクエリされない列にはインデックスを作成しないでください。
無視されたインデックス(INVISIBLE ではない)

インデックスを削除せずにオプティマイザーにスキップさせるには(削除前に本当に必要かをテストする場合に便利です)、MariaDB では MySQL の INVISIBLE ではなく、IGNORED を使用します。

-- ✅ MariaDB syntax (10.6+):
ALTER TABLE demo ALTER INDEX index_name IGNORED;
ALTER TABLE demo ALTER INDEX index_name NOT IGNORED;  -- re-enable

-- ✗ MySQL syntax — fails on MariaDB:
ALTER TABLE demo ALTER INDEX index_name INVISIBLE;

書き込み時もインデックスは引き続き維持されますが、オプティマイザーからは参照されません。主キーは無視できません。無視されたインデックスを参照してください。

インデックス付きカラムに対する関数

「インデックス付きカラムに関数を適用すると、インデックスは無効になる」という従来のルールは、MariaDB 11.1+ および 11.4 LTS では古くなっています。オプティマイザーは現在、よくある複数の関数パターンでインデックスを使用できます。

パターンインデックスを使用できますか?対応バージョン
WHERE YEAR(col) = 2025✅ — サーガブルで、適切な範囲を選択します11.1+ (MDEV-8320)
WHERE DATE(col) <= '2025-12-31'✅ — サーガブルです11.1+ (MDEV-8320)
大文字小文字を区別しない照合順序(例:utf8mb4_uca1400_ai_ci)での WHERE UPPER(varchar_col) = '...'✅ — sargable_casefold=ON がデフォルトです11.3+ (MDEV-31496)
WHERE SUBSTR(col, 1, n) = 'abc'✅ — 先頭部分を指定する SUBSTR は最適化されます11.8+ (MDEV-34911)
WHERE LOWER(case_sensitive_col) = '...'✗ — インデックスは使用されません(照合順序が大文字小文字を区別します)—
WHERE CAST(col AS UNSIGNED) = 1 またはその他の型を変更する変換✗ — インデックスは使用されません—

オプティマイザーがまだサーガブルにできない場合は、範囲条件に書き換えるパターンが引き続き有効です。

WHERE created_at >= '2025-01-01' AND created_at < '2026-01-01'

推測せずに EXPLAIN で確認してください。11.4+ では、「インデックスを使用しない」とされていた書き換えの多くが、現在は何の効果もありません。サーガブルなパターンで EXPLAIN にまだ type=ALL が表示される場合は、@@optimizer_switch の sargable_casefold を確認し、カラムの照合順序が _ci であることを確認してください。

関数インデックス:生成カラムを使用する

MySQL 8.0.13+ は、二重かっこ構文で式を直接インデックス化する関数キー部分をサポートしています。MariaDB はこれをサポートしていません。

-- ✗ MySQL syntax — fails on MariaDB:
CREATE INDEX idx_upper ON users ((UPPER(name)));
ALTER TABLE orders ADD INDEX ((total * quantity));

MariaDB では、代わりに生成(計算)カラムにインデックスを作成します。VIRTUAL カラムは何も保存せず、読み取り時に計算されます。そのカラムのインデックスには式の値が保持され、その値が検索対象になります。

-- ✅ MariaDB equivalent:
ALTER TABLE users
  ADD COLUMN name_upper VARCHAR(255) AS (UPPER(name)) VIRTUAL,
  ADD INDEX idx_name_upper (name_upper);

-- Query the column the optimizer can resolve directly,
-- or rely on virtual-column optimizer support (11.8+) for WHERE UPPER(name) = ...
SELECT * FROM users WHERE name_upper = 'ALICE';

多くの単純なケース(YEAR(col) や、_ci 照合順序での UPPER(col))では、MariaDB 11.1+ でインデックス付きの式は不要になっている点に注意してください。上の表を参照してください。式だけではサーガブルにならない場合に、生成カラムを使用します。

ページネーション:OFFSET ではなくカーソルベースを使用する

OFFSET は、見落としやすいパフォーマンス上の落とし穴です。LIMIT 10 OFFSET 50000 は、ページを読み込むたびに 50,000 行をスキャンして破棄します。

-- ✗ Slow — scans 50,000 rows to skip them:
SELECT id, title FROM posts ORDER BY id DESC LIMIT 10 OFFSET 50000;

-- ✅ Fast — index seek directly to the cursor position:
-- First page:
SELECT id, title FROM posts ORDER BY id DESC LIMIT 10;

-- Next page (pass last id from previous result as $last_id):
SELECT id, title FROM posts WHERE id < $last_id ORDER BY id DESC LIMIT 10;

フィルター付きクエリでは、id とともにフィルター対象のカラムもインデックスに含めます。

-- Query: WHERE category = 'news' ORDER BY id DESC
CREATE INDEX idx_cat_id ON posts (category, id);
-- Cursor query:
SELECT id, title FROM posts WHERE category = 'news' AND id < $last_id ORDER BY id DESC LIMIT 10;

次のページがあるかどうかを判定するには、LIMIT 11 を取得し、11 行目が存在するか確認します。

ヒストグラム統計

ヒストグラムを使うと、オプティマイザーはインデックスのないカラムのデータ分布を把握できます。複雑なクエリでクエリプランの品質を高めるうえで重要です。ヒストグラムがない場合、オプティマイザーは分布が均一だと仮定し、誤った結合順序を選ぶことがあります。

-- Collect histograms for a table (requires a full scan — run during low traffic):
ANALYZE TABLE orders;

-- Verify histograms were collected:
SELECT * FROM mysql.column_stats WHERE table_name = 'orders';

ANALYZE TABLE を実行するタイミング:

  • 大量のデータを挿入した後、またはデータに大きな変更を加えた後
  • EXPLAIN に予想外に大きな rows の推定値が表示された場合
  • テーブルを初めて作成してデータを読み込んだ後

データ分布に大きな偏りがあるテーブルでは、ヒストグラムの粒度を調整します。

SET histogram_size = 100;  -- default is 0 (disabled) in older versions, 254 in 10.4.3+
ANALYZE TABLE orders;

histogram_size > 0 を指定して ANALYZE TABLE を実行すると、ヒストグラムがカラムごとに自動収集されます。ヒストグラムは mysql.column_stats に保存され、optimizer_use_condition_selectivity >= 4 の場合に参照されます(10.4.1+ のデフォルト)。

MariaDB オプティマイザースイッチ

MariaDB のオプティマイザーには、MySQL よりも調整可能なフラグが多くあります。開発者にとって特に便利なフラグは次のとおりです。

-- See current settings:
SELECT @@optimizer_switch\G

-- Disable a specific optimization for a session (useful for debugging):
SET optimizer_switch = 'derived_merge=off';

-- Re-enable:
SET optimizer_switch = 'derived_merge=on';

特に影響の大きいフラグ:

フラグデフォルト効果
derived_mergeon派生テーブルを外側のクエリにマージします。通常、処理が高速になります
semijoinonIN/EXISTS サブクエリを最適化します。予期しないプランのデバッグ時は無効にしてください
subquery_cacheon相関サブクエリの結果をキャッシュします。同じサブクエリが繰り返される場合に大きな効果があります
rowid_filteron行を取得する前に rowid を事前フィルターします。範囲クエリに役立ちます
mrroffマルチレンジ読み取りです。回転ディスクで大規模な範囲スキャンを行う場合に有効にします

不適切なプランの原因となっている最適化を特定するため、フラグを一度に 1 つずつ無効にしてください。その後、デフォルト設定が代替設定よりも悪いプランを生成する場合は、JIRA で報告してください。

10.7~10.11 LTS期間のオプティマイザーの改善

10.11 LTS系列には、10.7~10.10の短期リリースで導入された機能が含まれています。

  • JSON形式のヒストグラム(10.8以降、MDEV-21130、MDEV-26519) — ヒストグラム統計がJSON形式で保存され、旧バイナリ形式よりも正確になります。10.8以降でANALYZE TABLEを実行するだけで、オプティマイザーのカーディナリティ推定が改善されます。
  • 降順インデックス(10.8以降、MDEV-13756) — CREATE INDEX idx ON t (a ASC, b DESC)がサポートされます。複合インデックスを使うORDER BY a, b DESCのパターンや、降順インデックスに対するMIN()/MAX()で役立ちます。
  • SHOW ANALYZE [FORMAT=JSON](10.9以降、MDEV-27021) — 別の接続で実行中のクエリについて、処理を妨げることなくオプティマイザープランと実行時の統計情報を取得できます。EXPLAIN FOR CONNECTION構文もサポートされています(MDEV-10000)。
  • eq_refテーブルが多数ある結合の最適化を改善(10.10以降、MDEV-28852、MDEV-26278) — スタースキーマ型の大規模な結合で、プランが大幅に改善されます。
  • ANALYZE FORMAT=JSONでオプティマイザー自体の処理時間を報告(10.11以降、MDEV-28926) — プランニング時間と実行時間を分けて表示します。
11.4 LTSのオプティマイザーの改善

11.4 LTS系列でも、改良が続いています。

  • 新しいコストベースのコストモデル(11.0以降) — 旧来のルールベースのヒューリスティックを、SSDやストレージエンジンごとの特性を考慮して調整されたモデルに置き換えます。同じクエリでも、10.6と11.4ではEXPLAINや結合順序の選択に目立った違いが出ることがあります。10.xで手動設定したoptimizer_adjust_secondary_key_costsがある場合は削除してください。11.4以降では何も行いません。
  • 単一テーブルのUPDATE/DELETEに対するセミジョイン最適化(11.1以降、MDEV-7487) — UPDATE/DELETE内のサブクエリでも、SELECTで使われるものと同じサブクエリの書き換え(マテリアライゼーション、セミジョインなど)を利用できるようになりました。書き換えなしで大幅な高速化が得られることもよくあります。
  • 定数とのDATE/YEAR比較をサーガブルに(11.1以降、MDEV-8320) — 上記のインデックス列に対する関数を参照してください。
  • サーガブルな大文字・小文字の変換(11.3以降、MDEV-31496、sargable_casefoldはデフォルトで有効) — 大文字・小文字を区別しない照合順序の列に対するUCASE/LCASE/UPPER/LOWERで、インデックスを使用できます。
11.5~11.8 LTSのオプティマイザーの改善

これらは現在のLTSのベースラインに含まれており、現在オプティマイザーができることを理解するうえで役立ちます。

  • パーティションテーブルでのインデックス条件プッシュダウン(11.5以降、MDEV-12404) — 以前はパーティションテーブルでICPを使用できませんでしたが、現在は使用できるようになり、パーティション化されたスキーマで大幅に高速化することもよくあります
  • プッシュダウンされたインデックス条件の選択性をANALYZEで表示(11.5以降、MDEV-18478) — ICPが効果を発揮しているかどうかの診断に役立ちます
  • 文字セット縮小最適化をデフォルトで有効化(11.8以降、MDEV-34380) — WHERE句で不要な文字セット変換をなくします
  • SUBSTR(col, 1, n) = const_strの最適化(11.8以降、MDEV-34911) — 条件が先頭部分を指定するSUBSTRであっても、オプティマイザーが列のインデックスを使用できるようになりました
  • オプティマイザーでの仮想列のサポート(11.8以降、MDEV-35616) — オプティマイザーでの仮想列のサポートを参照してください。以前は、仮想列はオプティマイザーからほとんど見えない状態でした
  • 単一テーブルのUPDATE/DELETEに対するコストベースのサブクエリ戦略(11.8以降、MDEV-25008) — オプティマイザーがコストに基づいてサブクエリ戦略を選択するようになりました
MariaDB 12.x のオプティマイザーの改善

12.x のローリングリリースでは、さらにいくつかの制限が解消されました。

  • 逆順スキャンでの Rowid フィルタリング(12.0 以降)— 以前は ORDER BY ... DESC クエリで Rowid フィルタリングを利用できませんでしたが、現在は利用できます
  • 逆順スキャンでのインデックス条件プッシュダウン(12.0 以降)— ICP にも同じ修正が適用されました
  • ルースインデックススキャン(「グループ化にインデックスを使用」)が DESC のキー部分で動作(12.0 以降)— 以前は ASC インデックスが必要でした
  • GROUP BY / ORDER BY で仮想カラムのインデックスを使用可能(12.1 以降)
  • 並べ替え可能な LEFT JOIN の最適化(12.3 以降)— オプティマイザーが、より多くの LEFT JOIN の組み合わせを並べ替えられるようになりました
  • DISTINCT GROUP BY カラムの推論(12.2 以降)— GROUP BY を含む派生テーブルのグループキーが個別の値であると認識され、後続処理でより多くの最適化が可能になります

11.8 LTS をベースラインとして使用していて、逆順または仮想カラムを使うクエリの実行計画が不必要に遅く見える場合、これらのいずれかが原因かもしれません。同じクエリを 12.x バージョンで実行して確認してください。

オプティマイザーヒント

MariaDB 12.0 では、包括的な MySQL-8 スタイルのオプティマイザーヒントフレームワーク(MDEV-35504)が導入され、12.1 および 12.2 でもヒントが追加されました。ヒントは SELECT の直後に /*+ ... */ コメントとして記述し、セッション設定を変更せずに、対象の 1 つのクエリでオプティマイザーの動作を上書きします。

SELECT /*+ JOIN_ORDER(o, c) */ *
FROM orders o JOIN customers c ON c.id = o.customer_id;

利用可能なヒント:

ヒント導入バージョン目的
QB_NAME(name)12.0クエリブロックに名前を付け、ほかのヒントから外部より指定できるようにします
JOIN_FIXED_ORDER / JOIN_ORDER(t1, t2, ...)12.0結合順序を強制します(JOIN_FIXED_ORDER は STRAIGHT_JOIN と似ています)
JOIN_PREFIX(t1, ...) / JOIN_SUFFIX(t1, ...)12.0特定のテーブルを結合順序の先頭または末尾に配置するよう強制します
MAX_EXECUTION_TIME(ms)12.0タイムアウトを超えて実行されたクエリを中断します
[NO_]MRR / [NO_]BKA / [NO_]BNL12.0Multi-Range Read、Batched Key Access、Block Nested Loop を切り替えます
[NO_]ICP12.0インデックス条件プッシュダウンを切り替えます
[NO_]RANGE_OPTIMIZATION12.0レンジオプティマイザーを切り替えます
SEMIJOIN(strategy, ...) / SUBQUERY(strategy)12.0サブクエリの書き換え方法を選択します
[NO_]INDEX(t idx, ...) / [NO_]JOIN_INDEX / [NO_]GROUP_INDEX / [NO_]ORDER_INDEX12.1用途に応じて特定のインデックスの使用を強制または禁止します
[NO_]SPLIT_MATERIALIZED / [NO_]DERIVED_CONDITION_PUSHDOWN / [NO_]MERGE12.1サブクエリおよび派生テーブルの最適化を制御します
[NO_]ROWID_FILTER / [NO_]INDEX_MERGE12.2Rowid フィルタリングとインデックスマージを切り替えます

QB_NAME() の例 — サブクエリに名前を付け、外側のヒントから指定できるようにします。

SELECT /*+ NO_MERGE(@sub) */ *
FROM (
    SELECT /*+ QB_NAME(sub) */ customer_id, COUNT(*) AS n
    FROM orders
    GROUP BY customer_id
) t
WHERE n > 10;

ヒントは SET optimizer_switch より対象を絞って適用できます。セッション全体ではなく、記述したクエリだけに適用されるためです。

高コストなクエリの制限:LIMIT ROWS EXAMINED

LIMIT ROWS EXAMINED は MariaDB 固有の拡張機能(5.5.21 以降)で、MySQL に相当する機能はありません。SELECT が調べる行数に上限を設け、上限に達すると実行を早期終了します。上限のないクエリやアドホッククエリで、スキャンが際限なく続くのを防ぐ安全策です。

-- Up to 10 result rows, but stop after examining 10,000 rows:
SELECT * FROM t1, t2 LIMIT 10 ROWS EXAMINED 10000;

-- The cap can be used on its own:
SELECT * FROM big_table WHERE status = 'x' LIMIT ROWS EXAMINED 50000;

上限に達すると、クエリは部分的な結果セットと警告を返します。そのため、これは安全策であり、正確な結果をより速く取得する方法ではありません。対象は SELECT のみです。UPDATE や DELETE では構文エラーになります。時間ベースで制限する場合は、上記の MAX_EXECUTION_TIME(ms) オプティマイザーヒント(12.0 以降)を使用してください。LIMIT ROWS EXAMINED を参照してください。

すぐに実行できるチェックリスト

インデックスを追加したりクエリを書き換えたりする前に、まず次の項目を確認してください。

  1. 起動時に performance_schema=ON になっていることを確認します(オフの場合は再起動が必要です)— パフォーマンススキーマの概要
  2. 遅いクエリに対して EXPLAIN を実行し、実際に時間がかかっている箇所を確認します
  3. ANALYZE TABLE を実行します — 統計情報が古いと、適切でない実行計画になる原因になります
  4. WHERE 句でインデックス付き列に関数を適用していないか確認します — ただし、多くの場合、11.4+ では現在、検索条件として利用できます(_ci 照合順序での YEAR()、DATE()、UPPER())
  5. ページネーションクエリで OFFSET を使っていないか確認します
  6. 複合インデックスの列順がクエリの述語に合っていることを確認します(左端プレフィックス)
  7. EXPLAIN の Extra 列で Using filesort または Using temporary がないか確認します — これらは、インデックスが不足している、または列順が適切でないことを示す場合がよくあります

参考資料

ここで扱っていないトピックについては、mariadb.com/docs にある MariaDB 公式ドキュメントを参照してください。

コメント