Issue #2261669 by Berdir, timmillwood, jhedstrom: Slow query in NodeRevisionAccessCheck

8.0.x
Nathaniel Catchpole 2015-07-10 21:38:00 +01:00
parent 6b95f9a850
commit a9298fb6f5
4 changed files with 112 additions and 26 deletions

View File

@ -906,7 +906,9 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
$schema = array(
'description' => "The data table for $entity_type_id entities.",
'primary key' => array($id_key, $entity_type->getKey('langcode')),
'indexes' => array(),
'indexes' => array(
$entity_type_id . '__id__default_langcode__langcode' => array($id_key, $entity_type->getKey('default_langcode'), $entity_type->getKey('langcode')),
),
'foreign keys' => array(
$entity_type_id => array(
'table' => $this->storage->getBaseTable(),
@ -942,7 +944,9 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
$schema = array(
'description' => "The revision data table for $entity_type_id entities.",
'primary key' => array($revision_key, $entity_type->getKey('langcode')),
'indexes' => array(),
'indexes' => array(
$entity_type_id . '__id__default_langcode__langcode' => array($id_key, $entity_type->getKey('default_langcode'), $entity_type->getKey('langcode')),
),
'foreign keys' => array(
$entity_type_id => array(
'table' => $this->storage->getBaseTable(),
@ -1017,6 +1021,9 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
* A partial schema array for the base table.
*/
protected function processDataTable(ContentEntityTypeInterface $entity_type, array &$schema) {
// Marking the respective fields as NOT NULL makes the indexes more
// performant.
$schema['fields'][$entity_type->getKey('default_langcode')]['not null'] = TRUE;
}
/**
@ -1031,6 +1038,9 @@ class SqlContentEntityStorageSchema implements DynamicallyFieldableEntityStorage
* A partial schema array for the base table.
*/
protected function processRevisionDataTable(ContentEntityTypeInterface $entity_type, array &$schema) {
// Marking the respective fields as NOT NULL makes the indexes more
// performant.
$schema['fields'][$entity_type->getKey('default_langcode')]['not null'] = TRUE;
}
/**

View File

@ -22,22 +22,12 @@ class NodeStorageSchema extends SqlContentEntityStorageSchema {
protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
$schema = parent::getEntitySchema($entity_type, $reset);
// Marking the respective fields as NOT NULL makes the indexes more
// performant.
$schema['node_field_data']['fields']['default_langcode']['not null'] = TRUE;
$schema['node_field_revision']['fields']['default_langcode']['not null'] = TRUE;
$schema['node_field_data']['indexes'] += array(
'node__default_langcode' => array('default_langcode'),
'node__frontpage' => array('promote', 'status', 'sticky', 'created'),
'node__status_type' => array('status', 'type', 'nid'),
'node__title_type' => array('title', array('type', 4)),
);
$schema['node_field_revision']['indexes'] += array(
'node__default_langcode' => array('default_langcode'),
);
return $schema;
}
@ -73,7 +63,6 @@ class NodeStorageSchema extends SqlContentEntityStorageSchema {
case 'changed':
case 'created':
case 'langcode':
// @todo Revisit index definitions:
// https://www.drupal.org/node/2015277.
$this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
@ -81,14 +70,6 @@ class NodeStorageSchema extends SqlContentEntityStorageSchema {
}
}
if ($table_name == 'node_field_revision') {
switch ($field_name) {
case 'langcode':
$this->addSharedTableFieldIndex($storage_definition, $schema, TRUE);
break;
}
}
return $schema;
}

View File

@ -0,0 +1,42 @@
<?php
/**
* @file
* Contains \Drupal\system\Tests\Entity\Update\SqlContentEntityStorageSchemaIndexTest.
*/
namespace Drupal\system\Tests\Entity\Update;
use Drupal\system\Tests\Update\UpdatePathTestBase;
/**
* Tests that a newly-added index is properly created during database updates.
*
* @group Entity
*/
class SqlContentEntityStorageSchemaIndexTest extends UpdatePathTestBase {
/**
* {@inheritdoc}
*/
public function setUp() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../tests/fixtures/update/drupal-8.bare.standard.php.gz',
];
parent::setUp();
}
/**
* Test for the new index.
*/
public function testIndex() {
$this->assertTrue(db_index_exists('node_field_data', 'node__default_langcode'), 'Index node__default_langcode exists prior to running updates.');
$this->assertFalse(db_index_exists('node_field_data', 'node__id__default_langcode__langcode'), 'Index node__id__default_langcode__langcode does not exist prior to running updates.');
$this->assertFalse(db_index_exists('users_field_data', 'user__id__default_langcode__langcode'), 'Index users__id__default_langcode__langcode does not exist prior to running updates.');
$this->runUpdates();
$this->assertFalse(db_index_exists('node_field_data', 'node__default_langcode'), 'Index node__default_langcode properly removed.');
$this->assertTrue(db_index_exists('node_field_data', 'node__id__default_langcode__langcode'), 'Index node__id__default_langcode__langcode properly created on the node_field_data table.');
$this->assertTrue(db_index_exists('users_field_data', 'user__id__default_langcode__langcode'), 'Index users__id__default_langcode__langcode properly created on the user_field_data table.');
}
}

View File

@ -502,6 +502,15 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
),
));
$this->setUpStorageDefinition('default_langcode', array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'tiny',
),
),
));
$expected = array(
'entity_test' => array(
'description' => 'The base table for entity_test entities.',
@ -531,10 +540,21 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array('id', 'langcode'),
'unique keys' => array(),
'indexes' => array(),
'indexes' => array(
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
'table' => 'entity_test',
@ -547,7 +567,9 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
$this->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$non_data_fields = array_keys($this->storageDefinitions);
unset($non_data_fields[array_search('default_langcode', $non_data_fields)]);
$table_mapping->setFieldNames('entity_test', $non_data_fields);
$table_mapping->setFieldNames('entity_test_field_data', array_keys($this->storageDefinitions));
$this->storage->expects($this->any())
@ -604,6 +626,14 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
),
),
));
$this->setUpStorageDefinition('default_langcode', array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'tiny',
),
),
));
$expected = array(
'entity_test' => array(
@ -677,11 +707,21 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array('id', 'langcode'),
'unique keys' => array(),
'indexes' => array(
'entity_test__revision_id' => array('revision_id'),
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
@ -705,10 +745,21 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array('revision_id', 'langcode'),
'unique keys' => array(),
'indexes' => array(),
'indexes' => array(
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
'table' => 'entity_test',
@ -725,8 +776,10 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
$this->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping->setFieldNames('entity_test_revision', array_keys($this->storageDefinitions));
$non_data_fields = array_keys($this->storageDefinitions);
unset($non_data_fields[array_search('default_langcode', $non_data_fields)]);
$table_mapping->setFieldNames('entity_test', $non_data_fields);
$table_mapping->setFieldNames('entity_test_revision', $non_data_fields);
$table_mapping->setFieldNames('entity_test_field_data', array_keys($this->storageDefinitions));
$table_mapping->setFieldNames('entity_test_revision_field_data', array_keys($this->storageDefinitions));