Virtual columns in MySQL and MariaDB

Virtual columns in MySQL and MariaDBIn this blog post, we’ll compare virtual columns in MySQL and MariaDB.

Virtual columns are one of my top features in MySQL 5.7: they can store a value that is derived from one or several other fields in the same table in a new field. It’s a very good way to build a functional index. This feature has been available in MariaDB for some time, so let’s compare the two and see if they are equivalent.


The MariaDB documentation is very easy to find.

Finding the documentation for virtual columns in 5.7 is a bit more challenging. Here is the best link I’ve found.

The MariaDB documentation isn’t clear when you should use a persistent column rather than a virtual one. If you read carefully, you’ll see that indexes are only supported on persistent columns, but the pros and cons of both options could have been better presented.

For MySQL, there is one interesting paragraph listing the potential use cases for stored columns and virtual columns. This paragraph is not super visible, but the gist of it is “always use a virtual column except if the value is too expensive to evaluate on the fly.” Note that you don’t need to use a stored column to index it in 5.7.


Creating a virtual column is very similar in both systems:

Note that NOT NULL is not supported with MariaDB while it’s allowed in 5.7:

When creating a materialized virtual column, the syntax is unfortunately not identical: MariaDB has PERSISTENT columns while 5.7 has STORED columns. It doesn’t look like a big deal, but it’s another item to add to a checklist before a migration.

Adding a virtual column

Great! Creating the column is only a metadata change, so it runs nearly instantly whatever the size of the table is.

With MariaDB, it’s quite different:

Yes, a full table rebuild was needed. And if we are running some sysbench insert workload, we can easily see that this is not an online rebuild – for around 1/3 of the schema change, writes were stalled:


That’s probably one of the most striking differences: with MariaDB, a column must be PERSISTENT for it to be indexed. This is not necessary in MySQL 5.7. The only situation when an indexed column in 5.7 must be STORED is when it’s a primary key.

When it comes to adding an index on several columns, some being regular columns and some being virtual columns, both versions allow this action:

The big difference though is that adding the index is performed online in 5.7, while it’s a blocking operation in MariaDB 10.


While at first sight MariaDB 10 and MySQL 5.7 offer very similar features with virtual columns, the reality is quite different: for virtual columns in MySQL and MariaDB the syntax is not exactly the same, adding a virtual column is not done the same way and indexing sets different constraints. The MySQL 5.7 implementation seems more polished for production usage with large tables and/or heavy traffic.

Share this post

Comments (6)

  • Peter Laursen

    There is one more important difference as described (by me) here:

    March 5, 2016 at 7:58 am
  • Mary

    It is a little bit hard for understanding, but thank you for the article. I am going to try it with MySQL. Hope, everything will be OK!

    March 9, 2016 at 5:12 am
  • MAEDA Atsushi


    Thank you for your nice article.
    I translated this into Japanese for users in Japan.
    Translated one is as follows

    If there is any problem, please get in touch with me.
    thank you.

    March 14, 2016 at 5:14 am
  • Balazs

    Thank you, but it defeats itself in the examples; you cannot just throw around things like
    “ALTER TABLE sbtest1 ADD reverse_pad char(60) GENERATED ALWAYS AS (reverse(pad)) VIRTUAL;”
    What is reverse, what is pad?

    October 31, 2016 at 9:44 am
    • Balazs

      Actually once you get past the facts that “reverse” is a rarely used function in mysql, and “pad” is an example column name, this is quite good.

      October 31, 2016 at 12:56 pm
  • lirezh

    Indexes of virtual columns in Mysql 8.0 and likely older is seriously bugged.
    Not recommended.
    Performance will degrade over time as it doesn’t refresh content with every update resulting in partial fulltable scans.
    You can verify that using EXPLAIN syntax and compare the counters with count()

    January 25, 2019 at 3:30 pm

Comments are closed.

Use Percona's Technical Forum to ask any follow-up questions on this blog topic.