Using Persistent Computed Columns
On this page
A computed column is a column defined by an expression that uses other columns in the table.
There are storage and performance tradeoffs to consider when using computed columns.
-
Parsing JSON objects for improved read performance
-
Precomputing a value using an expression that includes values from other columns in the table
-
Extracting values from a column, such as a year from a timestamp or a domain from a URL
-
Pre-materializing common expressions in queries allowing them to be used in high-order operations, such as segment elimination or encoded
GROUP BY
s (see Encoded Data in Columnstores for more information) -
Using computed columns as sort keys, such as a timestamp type computed column (see Optimizing Table Data Structures for more information on sort keys)
Persistent computed columns can be created as part of a CREATE TABLE statement, or can be added later using ALTER TABLE.NOT NULL
constraint in CREATE TABLE
.NOT NULL
constraint using ALTER TABLE
is not supported.
Computed Column Examples
The following statement creates a table col_
with an INT
column col_
and a persistent computed column col_
that is defined using an expression that takes the value in col_
and adds 1
to it.
CREATE TABLE cal_test (col_a INT PRIMARY KEY, col_b AS col_a + 1PERSISTED BIGINT, SORT KEY(col_b));
Inserting values into column col_
will automatically populate column col_
using the column definition expression.
INSERT INTO cal_test (col_a) VALUES (1), (2);SELECT * FROM cal_test;
+-------+-------+
| col_a | col_b |
+-------+-------+
| 2 | 3 |
| 1 | 2 |
+-------+-------+
It is possible to create a table with computed columns initialized using a NOT NULL
constraint, just like a non-computed column.
CREATE TABLE cal_test (col_a int NOT NULL, col_b AS col_a+1 PERSISTED BIGINT NOT NULL);DESC cal_test;
+-------+---------+------+------+---------+----------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+------+---------+----------+
| col_a | int(11) | NO | | NULL | |
| col_b | int(11) | NO | | NULL | computed |
+-------+---------+------+------+---------+----------+
It is also possible to add a computed column to an existing table using ALTER TABLE.
CREATE TABLE cal_test (col_a INT, col_b INT);INSERT INTO cal_test (col_a, col_b) VALUES (15, 9), (45, 81);ALTER TABLE cal_test ADD col_c AS (col_a + col_b/2) PERSISTED BIGINT;SELECT * FROM cal_test;
+---+-------------------+
| col_a | col_b | col_c |
+-------+-------+-------+
| 15 | 9 | 20 |
| 45 | 81 | 86 |
+-------+-------+-------+
DESC cal_test;
+-------+---------+------+------+---------+----------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+------+---------+----------+
| col_a | int(11) | YES | | NULL | |
| col_b | int(11) | YES | | NULL | |
| col_c | int(11) | YES | | NULL | computed |
+-------+---------+------+------+---------+----------+
Adding a computed column with a NOT NULL
constraint using ALTER TABLE
will result in an error.
ALTER TABLE cal_test ADD col_c AS (col_a + col_b/2)PERSISTED BIGINT NOT NULL;
ERROR 1064 ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near 'NOT NULL' at line 1
Attempts to insert values directly into a computed column will result in an error, even if the values are correct
with respect to the column definition.
INSERT INTO cal_test (col_a, col_b, col_c) VALUES (3, 4, 2);
ERROR 1822 ER_MEMSQL_COMPUTED_INSERT: Cannot insert into computed column 'col_c'
A computed column can be created using any expression that outputs a value that is a valid SingleStore data type, composed of operators and built-in functions.rand()
and now()
cannot be used in computed columns.
SELECT * FROM j;
+---+-------------------------------------------------+
| a | b |
+---+-------------------------------------------------+
| 1 | {"name":"Sandy Beach","occupation":"lifeguard"} |
+---+-------------------------------------------------+
ALTER TABLE j ADD COLUMN occupation AS b::$occupation PERSISTED LONGTEXT;SELECT * FROM j;
+---+-------------------------------------------------+------------+
| a | b | occupation |
+---+-------------------------------------------------+------------+
| 1 | {"name":"Sandy Beach","occupation":"lifeguard"} | lifeguard |
+---+-------------------------------------------------+------------+
Modifying values in a column used to define a computed column will also update the affected values in the computed column.
UPDATE j SET b::$occupation = 'circus clown';SELECT * FROM j;
+---+----------------------------------------------------+--------------+
| a | b | occupation |
+---+----------------------------------------------------+--------------+
| 1 | {"name":"Sandy Beach","occupation":"circus clown"} | circus clown |
+---+----------------------------------------------------+--------------+
Computed Column Matching
The keyword AUTO has been added when using computed columns.
Instead of using the syntax:
CREATE TABLE test_cal(col_a int, col_b AS col_a * col_a PERSISTED int);
Use the word AUTO
in place of the expression type:
CREATE TABLE auto_cal(col_a int, col_b AS col_a * col_a PERSISTED AUTO);
This example uses the table created above and specifies the expression type.
EXPLAIN SELECT col_a, col_a*col_a FROM test_cal;
+-------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------+
| WARNING: Computed column test_cal.col_b of type [int(11) NULL] |
| does not match similar expression's type. Consider changing the |
| computed column's type to that of the expression [bigint(21) |
| NULL] |
| Project [test_cal.col_a, test_cal.col_a * test_cal.col_a AS |
| 'col_a*col_a'] |
| |
| ColumnStoreScan ticket_test.test_cal, KEY __UNORDERED () USING |
| CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+-------------------------------------------------------------------+
The following uses the table created above and uses AUTO
for the expression type.
EXPLAIN SELECT col_a, col_a*col_a FROM auto_cal;
+-------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------+
| Project [auto_cal.col_a, auto_cal.col_b AS `col_a*col_a`] |
| ColumnStoreScan ticket_test.auto_cal, KEY __UNORDERED () USING |
| CLUSTERED COLUMNSTORE table_type:sharded_columnstore |
+-------------------------------------------------------------------+
Use SHOW CREATE TABLE <table_
to see the persisted column expression when the expression type is specified.
SHOW CREATE TABLE test_cal;
+-----------+------------------------------------------------------+
| Table | Create Table |
+-----------+------------------------------------------------------+
| test_cal | CREATE TABLE `test_cal` (`col_a` int(11) DEFAULT |
| | NULL,`col_b` as col_a * col_a PERSISTED int(11), |
| | KEY `__UNORDERED` () USING CLUSTERED COLUMNSTORE, |
| | SHARD KEY () )AUTOSTATS_CARDINALITY_MODE=INCREMENTAL |
| | AUTOSTATS_HISTOGRAM_MODE=CREATE AUTOSTATS_SAMPLING=ON|
| | SQL_MODE='STRICT_ALL_TABLES' |
+-----------+------------------------------------------------------+
Use SHOW CREATE TABLE <table_
to see the persisted column and when using AUTO
.
SHOW CREATE TABLE auto_cal;
+-----------+------------------------------------------------------+
| Table | Create Table |
+-----------+------------------------------------------------------+
| auto_cal | CREATE TABLE `auto_cal` (`col_a` int(11) DEFAULT |
| | NULL,`col_b` as col_a * col_a PERSISTED bigint(21), |
| | KEY `__UNORDERED` () USING CLUSTERED COLUMNSTORE, |
| | SHARD KEY () )AUTOSTATS_CARDINALITY_MODE=INCREMENTAL |
| | AUTOSTATS_HISTOGRAM_MODE=CREATE AUTOSTATS_SAMPLING=ON|
| | SQL_MODE='STRICT_ALL_TABLES' |
+-----------+------------------------------------------------------+
Last modified: May 4, 2023