Problem/Motivation

#3343634: Add "json" as core data type to Schema and Database API provides the ability to use JSON columns. After that's done, we'll need the ability to add indexes for the data in those columns.

There are two ways to achieve this: indexes on SQL expressions or indexes on generated columns. Expression indexes were attempted in the issue mentioned above, but they're not supported by MariaDB, and it's not realistic to exclude such a large user base from this.

Therefore, the only remaining option is to add support for generated columns, which can then be part of indexes just like regular ones.

References:
MySql: https://dev.mysql.com/doc/refman/9.7/en/create-table-generated-columns.html
MariaDb: https://mariadb.com/docs/server/reference/sql-statements/data-definition...
PostgreSql: https://www.postgresql.org/docs/current/ddl-generated-columns.html
SQLite: https://sqlite.org/gencol.html

Proposed resolution

Allow creating generated columns in the DB Schema Definition API.

Stored vs. virtual

A stored generated column computes its value on write and keeps it on disk, like a regular column. A virtual one computes it on read and stores nothing.

Virtual columns are worth having because one of the major points of this issue is indexing. MySQL, MariaDB and SQLite can all index a virtual generated column, so you pay for the index but not for a second copy of the data. For a JSON column that's a real saving: the extracted value can be large, and it's already in the JSON document.

PostgreSQL is the exception. It only supports virtual generated columns from version 18, and it cannot index them (which also rules out unique constraints on them). Portable code should therefore use stored, and that's what the API docs recommend.

Remaining tasks

Nope.

API changes

  • Column::generated() adds the definition of a generated table column.
  • Drupal\Core\Database\SchemaDefinition\GeneratedColumnStorage enumerates the possible storage options for the generated column.

Data model changes

Nope.

Release notes snippet

TBD.

CommentFileSizeAuthor
#42 mr-diff.patch7.04 KBamateescu

Issue fork drupal-3586688

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

amateescu created an issue. See original summary.

amateescu’s picture

Title: [PP-1] Add support for generated columns to the DB Schema API » Add support for generated columns to the DB Schema API

This doesn't really need to be postponed.

mondrake’s picture

Issue summary: View changes

mondrake’s picture

mondrake’s picture

Status: Active » Needs review

All 3 core supported dbs implemented. The MR is reviewable, accepting that is built on top of #3411490: Replace array-based DB Schema API with a value object structure.

mondrake’s picture

Title: Add support for generated columns to the DB Schema API » [PP-1] Add support for generated columns to the DB Schema API
Issue summary: View changes
Status: Needs review » Postponed
mondrake’s picture

Title: [PP-1] Add support for generated columns to the DB Schema API » Add support for generated columns to the DB Schema API
Status: Postponed » Active
mondrake’s picture

mondrake’s picture

Title: Add support for generated columns to the DB Schema API » [PP-1] Add support for generated columns to the DB Schema API
Status: Active » Postponed
amateescu’s picture

Title: [PP-1] Add support for generated columns to the DB Schema API » Add support for generated columns to the DB Schema API
Status: Postponed » Needs work

The blocker is in :)

mondrake’s picture

Issue summary: View changes
Status: Needs work » Needs review
daffie’s picture

Status: Needs review » Needs work
daffie’s picture

Issue summary: View changes
amateescu’s picture

Status: Needs work » Needs review

Addressed all the reviews, and I think this is ready now.

mondrake’s picture

Filed #3616311: Deprecate Column::$dbSpecificExtra and Table::$dbSpecificExtra so we can start discussing about how to make the new API really db abstract.

daffie’s picture

Status: Needs review » Needs work

amateescu’s picture

Status: Needs work » Needs review

Removed the pgsql guard for virtual columns from the main MR, and started a new one for 11.x with it included.

mondrake’s picture

Looks very good to me now, cannot RTBC but +1 on that.

daffie’s picture

Status: Needs review » Needs work
Issue tags: +Needs change record updates, +Needs issue summary update

All my remarks have been addressed on the PR.
The PR is for me RTBC.
However the IS and the CR need to be updated.

mondrake’s picture

Issue summary: View changes
mondrake’s picture

Status: Needs work » Needs review
Issue tags: -Needs change record updates, -Needs issue summary update

Rebased and updated CR and IS.

mondrake’s picture

Title: Add support for generated columns to the DB Schema API » Add support for generated columns to the DB Schema Definition API
daffie’s picture

Status: Needs review » Reviewed & tested by the community

The updated IS and CR look good to me.
For me is it RTBC.

catch’s picture

Very excited for the possibilities this opens up.

Some of the sqlite schema introspection code is a bit painful, but unless there's some way to not expend that effort at all I doubt it can be simplified.

Apart from that, I only have one question:


 *       Prefer stored over virtual for portability: PostgreSQL supports virtual
 *       columns only from version 18 and cannot index them.

What's the reason we'd ever want a virtual generated column? When reading this, I was wondering if we should add it at all, but then I realised it would probably be harder to add support later if we hard-coded everything to stored, because we'd then have to change the APIs we're adding here. So maybe that's the answer but it would be good to flesh out in the issue summary.

amateescu’s picture

Issue summary: View changes

Virtual generated columns are very useful when disk space is a concern. MySQL, MariaDB and SQLite can all add indexes over them, so in that case you only pay the storage price for the index, not for the data as well.

Fleshed this out in the issue summary, and addressed the feedback on the MR :)

  • catch committed 0a09761f on 11.x
    feat: #3586688 Add support for generated columns to the DB Schema...

  • catch committed fa4fd791 on main
    feat: #3586688 Add support for generated columns to the DB Schema...
catch’s picture

Version: main » 11.x-dev
Status: Reviewed & tested by the community » Fixed

Thanks for the issue summary update + the MR changes. I can't find anything else to complain about here, so let's do it. Committed/pushed to main and 11.x, thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

driskell’s picture

Just wanted to share some experience here.

Generated columns are great but if you add an index to one in MySQL or MariaDB the metadata format twists slightly and becomes completely incompatible with the INSTANT alteration algorithm.

The impact is that for super large tables the resulting rebuild for any and all alterations (like adding a new column) would take hours and significant disk explosion instead of being instantaneous. Potentially meaning seemingly innocuous update code times out and takes out the site. Worse for Galera as the Total Order Isolation would subsequently take ALL connections offline until it complete.

Might be worth a word of warning somewhere as I’ve seen others bitten a few times with this.

Specifically adding an index to a generated columns is the killer. All table alterations become rebuilds and you lose all benefit from modern MySQL and MariaDB

amateescu’s picture

That's very useful info, thanks! Do you also have some numbers for what "super large" means.. tens of millions rows, or less?

driskell’s picture

Where I’ve seen the issue it’s been millions but it’s more I think the table size - e.g. gigabytes.

It just worth noting that with all modern engines the INSTANT kicks in most of the time so it does metadata only change and takes effect without impacting DML. But if INSTANT can’t be used and neither can INPLACE (for index on generated it can’t INPLACE either) it will hit COPY - that means copying gigabytes to a new table with no concurrent DML.

Of course there’s an element of you end up with COPY eventually anyway as there’s only so many INSTANT before it hits a limit but that’s at least one-off but if you make a table incompatible with INSTANT every single operation copies it.

mondrake’s picture

xjm’s picture

Status: Fixed » Needs work

This broke 11.x HEAD because it is not compatible with Posrgres 16. Per @longwave:

i dont think VIRTUAL is available until pgsql 18

  • xjm committed a56efd45 on 11.x
    Revert "feat: #3586688 Add support for generated columns to the DB...
xjm’s picture

Presumably we have three options:

  1. Come up with a fallback for Postgres 16
  2. Implement this some other way in the 11.x Postgres driver
  3. Allow 11.5 and 12.0 to violate the shared API policy for this one feature.

Leaving in D12 for now.

catch’s picture

I think we could skip the test on pgsql 16, and then any code that wants to rely on it would have to have an explicit pgsql 18 dependency.

amateescu’s picture

Status: Needs work » Reviewed & tested by the community
StatusFileSize
new7.04 KB

That's partly what the MR for the 11.x branch was doing. Looking at the revert diff, I noticed that the MR that was targeted for main was also committed to 11.x, but we had a 11.x-specific MR.

Reopened it, rebased on top of the latest 11.x, and attaching an interdiff between the two to clear up how we're handling pgsql 16.

catch’s picture

Kicking off postgresql runs on that MR just to double triple check before committing. My fault for committing the wrong MR to 11.x in the first place this one..

catch’s picture

Status: Reviewed & tested by the community » Fixed

Committed/pushed the correct MR to 11.x this time.., thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • catch committed cc6f9f57 on 11.x
    feat: #3586688 Add support for generated columns to the DB Schema...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.