Question: **Goal:**

Add a database index to a 'created' field.

**Given:**

There is a custom entity with a base field `created`.
The field is stored the entity table. 
Field source code of the `created` field:

```
$fields['created'] = BaseFieldDefinition::create('created')
  ->setLabel(t('Created'))
  ->setDescription(t('The time that the entity was created.'))
  ->setDisplayOptions('view', [
    'label' => 'hidden',
    'type' => 'timestamp',
    'weight' => 3,
    'settings' => [
      'date_format' => 'medium',
      'custom_date_format' => '',
      'timezone' => '',
    ],
  ])
  ->setDisplayConfigurable('view', TRUE);

```

**What I researched:**

I have not found a way to add index using the `\Drupal\Core\Field\BaseFieldDefinition()`.

As I understand indexes are defined in a `@FieldType` plugin. The `created` field is implemented via the `\Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem()` plugin and obviously does not have have indexes there.

P.S. I know, that I can write an updatescript to add an index to the table manually.

Answer: 
For those wondering which part from berdir's reply is necessary for creating an index on a base column - here is a full example on creating index on a string column `sku`:

`ekr_product/Entity/Product.php:`

```
<?php

 * @ContentEntityType(
...
 *     "storage_schema" = "Drupal\ekr_product\ProductStorageSchema",

```

`ekr_product/ProductStorageSchema.php:`

```
<?php

namespace Drupal\ekr_product;

use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
use Drupal\Core\Field\FieldStorageDefinitionInterface;

/**
 * Defines the node schema handler.
 */
class ProductStorageSchema extends SqlContentEntityStorageSchema {

  /**
   * {@inheritdoc}
   */
  protected function getSharedTableFieldSchema(FieldStorageDefinitionInterface $storage_definition, $table_name, array $column_mapping) {
    $schema = parent::getSharedTableFieldSchema($storage_definition, $table_name, $column_mapping);
    $field_name = $storage_definition->getName();

    switch ($field_name) {
      case 'sku':
        $this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
        break;
    }

    return $schema;
  }

}

```

Few comments on this.

You might be thinking why using method `getSharedTableFieldSchema` when creating index on the **base** table? Truly, *shared* word is sorta associated with fields stored in a separate tables. But from the function's documentation it follows that if your schema modification isn't cross-field you should use exactly this function.

Note also that the third parameter to `addSharedTableFieldIndex` is set to `TRUE`. Suddenly this makes the column you're creating index on `NOT NULL`. This is the same as if you'd be doing:

```
$schema['fields']['your_field']['not null'] = TRUE;

```

somewhere in schema overrides. This is a way to make the column **required** at the database level. 

HTH.
While the above API approaches are recommended, here's one more raw approach that can be useful for some cases. 

In this case, it adds an SQL index to a base field for the MySQL/MariaDB database engine:

```
/**
 * Add SQL index on published_date base field
 */
function MY_MODULE_update_8010(&$sandbox) {
  // Add index
  // ALTER TABLE $table ADD INDEX $name ($column1, $column2..)
  db_query("ALTER TABLE node_field_data ADD INDEX node_field__published_date (published_date)");
}

```