Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що означають IMMUTABLE, STABLE і VOLATILE у функціях і чому через них падають індекси?

Мінливість (volatility) - обіцянка, яку функція дає планувальнику про свою поведінку. Від неї залежить, які оптимізації PostgreSQL може застосувати.

Категорія Обіцянка Приклади
IMMUTABLE для тих самих аргументів завжди той самий результат, нічого не читає з бази lower(text), abs(), математика
STABLE той самий результат у межах одного оператора, може читати базу now(), функції, що залежать від налаштувань сесії
VOLATILE (за замовчуванням) результат може змінюватися навіть між рядками, можливі побічні ефекти random(), nextval(), clock_timestamp()

Що від цього залежить:

1. Індекси за виразом дозволені лише для IMMUTABLE-функцій:

CREATE INDEX ON users (lower(email));           -- працює
CREATE INDEX ON events ((created_at::date));    -- помилка для timestamptz
ERROR: functions in index expression must be marked IMMUTABLE

Приведення timestamptz до date залежить від часового поясу сесії, тож результат не незмінний. Рішення - зафіксувати пояс: ((created_at AT TIME ZONE 'UTC')::date).

2. Обчислення один раз: STABLE чи IMMUTABLE функцію з константними аргументами в WHERE планувальник може обчислити один раз і використати індекс. VOLATILE - викликається для кожного рядка, і індекс за нею не використати.

3. Згенеровані колонки й умови партицій теж вимагають IMMUTABLE.

Пастка - неправдива позначка. Власну функцію можна оголосити IMMUTABLE, навіть якщо вона читає таблицю:

CREATE FUNCTION tax_rate(country text) RETURNS numeric
LANGUAGE sql IMMUTABLE    -- неправда: читає таблицю
AS $$ SELECT rate FROM tax_rates WHERE code = country $$;

PostgreSQL повірить. Індекс за такою функцією зберігатиме значення на момент вставки, і після зміни tax_rates індекс поверне неправильні дані - тихо, без помилок. Кешовані плани підготовлених запитів теж можуть закріпити старий результат.

Правило: позначайте функцію найсуворішою категорією, яка справді правдива. Сумніви - STABLE чи VOLATILE. Вигода від неправдивого IMMUTABLE не варта пошкоджених даних.

Пов'язане - PARALLEL SAFE: чи можна виконувати функцію в паралельних воркерах. Власні функції за замовчуванням PARALLEL UNSAFE - це вимикає паралельні плани для запитів з ними.

У Laravel такі функції й індекси за виразами створюють у міграціях через DB::statement(), а запити мають використовувати точно той самий вираз, що в індексі (whereRaw('lower(email) = ?', [...])), інакше індекс не підхопиться.

Докладніше в документації: Категорії мінливості функцій

Схожі питання