1

This appears to be the prescribed way of deleting multiple node entities:

$nids = \Drupal::entityQuery('node')
  ->accessCheck(FALSE)
  ->condition('field_my_field', 'something')
  ->execute();

$storage_handler = \Drupal::entityTypeManager()->getStorage('node');

$entities = $storage_handler->loadMultiple($nids);

$storage_handler->delete($entities);

However, this takes a long time to execute. On my machine, the above code takes about 15 minutes to delete 100 entities. The same machine can programmatically create 100 entities in about 40 seconds -- not blazingly fast, but acceptable.

I also tried looping through the $nids to load and delete them one at a time. That runs about 10% faster, perhaps because the memory is released after each load. Still, it's too slow.

The relevant content type has about 30 fields. Perhaps this is a factor.

What if my application requires regularly deleting hundreds of entities, and it isn't practical to wait over an hour for the script to execute? Is there some other option for deleting large numbers of entities?

Drupal 10.2.3. PHP 8.1.16. MariaDB 10.4.28.

10
  • 2
    Is Drush an option? drush.org/12.x/commands/entity_delete
    – leymannx
    Commented Mar 25 at 18:31
  • 1
    It is hard to say here why deleting these individual entities is so slow. You may have to PHP profile to figure that out. As for processing large amounts of items offline, Drupal's queue API is the usual way and it is fully documented.
    – mona lisa
    Commented Mar 25 at 18:36
  • @leymannx Drush takes just as long -- about 15 minutes for 100 nodes. I suspect it runs the same code as I posted in my question.
    – arnoldbird
    Commented Mar 26 at 15:38
  • 1
    Whenever I suggest PHP profiling it tends to be ignored.
    – mona lisa
    Commented Mar 26 at 16:29
  • 1
    Yeah just to double down on that - you need to profile your site to find out why it takes so long to do something. Asking for people to guess from afar isn’t going to work for something like this. 40 seconds to create 100 nodes is very slow by today’s standards BTW. My 6 year old laptop takes less than 10 seconds to do the same, for comparison. But that’s on a site which doesn’t have any bottlenecks for entity deletion, which is the whole point - The problem is very narrowly scoped to your site and its implementation, it needs to be debugged by someone with full access to it
    – Clive
    Commented Mar 26 at 17:15

2 Answers 2

0

I found a way to delete thousands of nodes much more quickly.

Drupal can delete nodes much, much more quickly when the content type has no fields. With that in mind, this process allowed me to delete about 12,000 nodes in around a half an hour of work, even though my machines are on the slow side:

  1. Using drush or the config synchronization GUI, export the config for the content type, as well as both the field storage config and field config for all fields.
  2. Delete all the fields from the content type. This can be done via the GUI.
  3. Delete all the nodes using a script such as the one posted in the above question. See also the code sample below.
  4. Using drush or the config synchronization GUI, import the config you exported in step #1: Import the content type; import the field_storage for each field; import each field.

$content_type = 'my_content_type';
$roles = \Drupal::currentUser()->getRoles();

// Depending on your situation, it might be best to check if the user is an administrator.
if (in_array('administrator', $roles)) {

  $ids = \Drupal::entityQuery('node')
      ->accessCheck(TRUE)
      ->condition('type', $content_type)
      ->execute();

  // Avoid timeouts by doing 1000 at a time.
  $ids = array_slice($ids, 0, 1000);

  $storageHandler = \Drupal::entityTypeManager()->getStorage('node');

  $entities = $storageHandler->loadMultiple($ids);

  // This part takes a little while to run, but is dramatically faster when the content type has no fields.
  foreach ($entities as $entity) {
    $entity->delete();
  }
}
0

This code fetches node IDs matching a certain condition, loads those nodes into memory, and then deletes them.

By querying for IDs first, it efficiently retrieves only the nodes we want to delete. Finally, it deletes these nodes using the entity storage handler, ensuring proper handling of Drupal entities.

use Drupal\Core\Entity\EntityTypeManagerInterface;

// Get the IDs of nodes to delete.
$nids = \Drupal::entityQuery('node')
  ->condition('field_my_field', 'something')
  ->execute();

// Get the entity storage handler.
$entityStorage = \Drupal::entityTypeManager()->getStorage('node');

// Load the entities based on the IDs.
$entities = $entityStorage->loadMultiple($nids);

// Delete the loaded entities.
$entityStorage->delete($entities);
1
  • This is extremely slow when you have to delete hundreds (or thousands) of nodes and the content types have a couple dozen fields.
    – arnoldbird
    Commented May 6 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.