Згенерована колонка обчислюється з інших колонок того самого рядка за виразом.
CREATE TABLE order_items (
price DECIMAL(10, 2) NOT NULL,
quantity INT NOT NULL,
total DECIMAL(12, 2) AS (price * quantity) STORED
);
ALTER TABLE users
ADD COLUMN email_domain VARCHAR(255) AS (SUBSTRING_INDEX(email, '@', -1)) VIRTUAL,
ADD INDEX users_email_domain_idx (email_domain);
Два види:
VIRTUAL(за замовчуванням у MySQL) - не зберігається, обчислюється при читанні.STORED- обчислюється при записі й зберігається, як звичайна колонка.
Головна особливість MySQL - індекс на віртуальній колонці. InnoDB дозволяє вторинний індекс на VIRTUAL-колонці: значення обчислюються й зберігаються в індексі, але не в самій таблиці. Так індексують те, що інакше не проіндексувати:
Поле JSON:
ALTER TABLE products
ADD COLUMN brand VARCHAR(100) AS (attributes ->> '$.brand') VIRTUAL,
ADD INDEX products_brand_idx (brand);
SELECT * FROM products WHERE brand = 'Bosch'; -- використовує індекс
Вираз для пошуку без урахування регістру, дату з часу, нормалізоване значення.
Обмеження:
- Вираз - детермінований: без
NOW(),RAND(), змінних, підзапитів і посилань на інші таблиці. - Не можна записати значення напряму.
- Первинний ключ - лише на
STORED. - Зміна виразу
STORED-колонки - перебудова таблиці.
Функціональні індекси (MySQL 8.0.13+) - коротший запис того самого: індекс за виразом без явної колонки.
CREATE INDEX users_lower_email_idx ON users ((LOWER(email)));
Під капотом MySQL створює приховану віртуальну колонку. Щоб індекс спрацював, вираз у запиті має збігатися з виразом в індексі.
У Laravel-міграціях: $table->string('brand')->virtualAs("attributes->>'$.brand'") і ->storedAs(...).