Allow single-value base fields to be saved to dedicated database tables

Created on 19 November 2020, over 4 years ago
Updated 30 May 2023, about 2 years ago

Problem/Motivation

Right now Drupal core has logic to decide if base field data should be stored in the shared entity field data table (eg: node_field_data), or in a dedicated table (eg: node__myfield). This logic is contained in the DefaultTableMapping::allowsSharedTableStorage() method:

  /**
   * Checks whether the given field can be stored in a shared table.
   *
   * @param \Drupal\Core\Field\FieldStorageDefinitionInterface $storage_definition
   *   The field storage definition.
   *
   * @return bool
   *   TRUE if the field can be stored in a shared table, FALSE otherwise.
   */
  public function allowsSharedTableStorage(FieldStorageDefinitionInterface $storage_definition) {
    return !$storage_definition->hasCustomStorage() && $storage_definition->isBaseField() && !$storage_definition->isMultiple() && !$storage_definition->isDeleted();
  }

Thus, a field will be saved to the shared table storage if a) it does not have custom storage, AND b) it is a base field, AND c) it is not a multi-value field, AND d) it is not deleted.

This means that single-value base fields will ALWAYS be stored in the shared table. While this is beneficial to reducing the number of table JOINs required, it is not always desirable.

If a field is not required, it's possible to end up with a lot of empty cells / sparse data in the shared table, which could otherwise be avoided by a dedicated table. This is compounded by fields that add a lot of columns (like Geofields which add 9).

And more generally, it would be nice to provide the option to developers to explicitly declare that some fields should be stored in dedicated tables. Even though Drupal tries to abstract a lot of these low-level decisions, it is still useful to expose some of them to the developer so they can make the right choice for their particular application.

Proposed resolution

I propose we add two new methods to the BaseFieldDefinition class: setDedicatedTable() and hasDedicatedTable()

The latter can then be added as an additional condition in the allowsSharedTableStorage() method logic (described above).

Thus, a developer defining a new base field could do something like this to specify that the field data should be saved in a dedicated table:

$fields['myfield'] = BaseFieldDefinition::create('string')
  ->setLabel(t('My field'))
  ->setDedicatedTable(TRUE);

The method names setDedicatedTable() and hasDedicatedTable() were chosen to match the existing pattern set by setCustomStorage() and hasCustomStorage() methods, but open to other ideas if you think those don't perfectly convey their purpose.

Remaining tasks

... (tbd)

User interface changes

None.

API changes

This would change the API surface of FieldStorageDefinitionInterface to have an additional method: hasDedicatedTable() (returns boolean true/false).

Data model changes

None.

Release notes snippet

... (tbd)

Feature request
Status

Active

Version

9.2

Component
Field 

Last updated 2 days ago

Created by

🇺🇸United States m.stenta

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

Production build 0.71.5 2024