Kodokon kodokon.com

高度なインデックス:複合、カバリング、無視されるインデックス

左端プレフィックスの規則、カバリングインデックス、そしてインデックスをプランナーから見えなくする落とし穴を使いこなしましょう。

11 分 · 3 問

このレッスンを Kodokon で開く

複合インデックスは、宣言された順序に従って、複数の列にまたがって行を並べます。決定的な規則は左端プレフィックスです。(a, b)のインデックスは、aのフィルター、あるいはaかつbのフィルターには役立ちますが、b単体には決して役立ちません。したがって列の順序は些細なことではなく、設計上の選択です。まずは下のデータセットを作成しましょう。

SQL
CREATE TABLE employees (
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  department_id INTEGER,
  salary INTEGER NOT NULL
);

INSERT INTO employees
  (id, name, department_id, salary)
VALUES
  (1, 'Ada',    1, 65000),
  (2, 'Grace',  1, 72000),
  (3, 'Alan',   2, 58000),
  (4, 'Edsger', 1, 90000);
複合インデックスのためのテストテーブル。

(department_id, salary)にインデックスを作成しましょう。department_idから始まるフィルターはSEARCHを引き起こします。しかしsalaryだけのフィルターは左端プレフィックスを崩します。プランナーは正しい行へ直接飛べず、SCANに戻ります。二つのプランを比べてみましょう。

SQL
CREATE INDEX idx_dept_salary
  ON employees (department_id, salary);

-- Leftmost prefix present: index used
EXPLAIN QUERY PLAN
SELECT id FROM employees
WHERE department_id = 1
  AND salary > 60000;
-- SEARCH ... USING INDEX idx_dept_salary

-- Leading column missing: index ignored
EXPLAIN QUERY PLAN
SELECT id FROM employees
WHERE salary > 60000;
-- SCAN employees
同じインデックスが、一方のケースには役立ち、もう一方には役立たない。

カバリングインデックスは、クエリが読むすべての列を含みます。するとプランナーはテーブルを開かずに、インデックスから直接答えを返します。それがUSING COVERING INDEXの意味です。ここでは、インデックス(department_id, salary)が、その二つの列だけを読むクエリをカバーします。id(rowid)はすべてのインデックスに暗黙的に存在するので、これも無償でカバーされることを覚えておきましょう。

SQL
-- Every column read is in the index
EXPLAIN QUERY PLAN
SELECT department_id, salary
FROM employees
WHERE department_id = 1;
-- SEARCH employees USING COVERING INDEX
-- idx_dept_salary (department_id=?)
インデックスだけで答え、テーブルは開かれない。

理解度チェック

このレッスンの要点をしっかり覚えているか確認しましょう。

  1. (department_id, salary)の複合インデックスがあるとき、それを使えないクエリはどれですか?
    • WHERE department_id = 1
    • WHERE department_id = 1 AND salary > 60000
    • WHERE salary > 60000
    • WHERE department_id = 1 AND name = 'Ada'
  2. カバリングインデックスとは何ですか?
    • 読まれるすべての列を含み、テーブルを開くのを避けるインデックス
    • 複数のテーブルを一度にカバーするインデックス
    • 各INSERTのあとに自動で作り直されるインデックス
    • 主キーに対する一意インデックスの別名
  3. これらの条件のうち、emailに対する単純なインデックスの使用を妨げるのはどれですか?
    • WHERE email = 'a@b.co'
    • WHERE email > 'm'
    • WHERE lower(email) = 'a@b.co'
    • WHERE email IN ('a@b.co', 'c@d.co')