MySQL

MySQL 8.0 Generated Columns: Virtual, Stored, and JSON Index Extraction

Use MySQL 8.0 generated columns to index computed values, JSON paths, and date parts. Covers virtual vs stored tradeoffs and functional index patterns.

JusDB Team
November 10, 2025
5 min read
232 views

Generated columns in MySQL 8.0 let you define a column whose value is derived from an expression. They enable indexing computed values, JSON path extraction, and pre-computed business logic.

Virtual vs Stored Generated Columns

  • VIRTUAL (default): computed on every read, not stored on disk
  • STORED: computed on write and persisted to disk — can be indexed
sql
CREATE TABLE orders (
  id         INT AUTO_INCREMENT PRIMARY KEY,
  amount     DECIMAL(10,2),
  tax_rate   DECIMAL(5,4) DEFAULT 0.08,
  -- Virtual: computed on read, zero storage cost
  tax_amount DECIMAL(10,2) GENERATED ALWAYS AS (amount * tax_rate) VIRTUAL,
  -- Stored: computed on write, can be indexed
  total      DECIMAL(10,2) GENERATED ALWAYS AS (amount * (1 + tax_rate)) STORED
);

-- Create index on stored generated column
CREATE INDEX idx_orders_total ON orders (total);

JSON Path Extraction Index

sql
CREATE TABLE products (
  id       INT AUTO_INCREMENT PRIMARY KEY,
  metadata JSON,
  -- Extract and index a JSON field
  sku      VARCHAR(50) GENERATED ALWAYS AS (metadata->>'$.sku') STORED,
  category VARCHAR(50) GENERATED ALWAYS AS (metadata->>'$.category') STORED
);

CREATE INDEX idx_products_sku ON products (sku);
CREATE INDEX idx_products_category ON products (category);

-- Now these queries use indexes efficiently
SELECT * FROM products WHERE sku = 'WP-001';
SELECT * FROM products WHERE category = 'electronics';

Date Part Extraction

sql
CREATE TABLE events (
  id         BIGINT AUTO_INCREMENT PRIMARY KEY,
  event_time DATETIME NOT NULL,
  event_year SMALLINT GENERATED ALWAYS AS (YEAR(event_time)) STORED,
  event_month TINYINT GENERATED ALWAYS AS (MONTH(event_time)) STORED
);

CREATE INDEX idx_events_year_month ON events (event_year, event_month);

-- Fast query by year/month without function on indexed column
SELECT count(*) FROM events WHERE event_year = 2025 AND event_month = 10;

Key Takeaways

  • Use STORED generated columns when you need to index the computed value
  • Use VIRTUAL generated columns for computed display values — zero storage overhead
  • JSON path generated columns are the canonical way to index JSON fields in MySQL
  • Generated columns cannot reference other generated columns or non-deterministic functions

JusDB Can Help

Generated columns simplify many schema design challenges. JusDB can help you identify where generated columns can improve your query performance.

Share this article

JusDB Team

Official JusDB content team