Closed (fixed)
Project:
Entity Usage
Version:
5.x-dev
Component:
Code
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Reporter:
Created:
3 Dec 2025 at 15:49 UTC
Updated:
10 Apr 2026 at 19:30 UTC
Jump to comment: Most recent
for a data point, on one project entity_usage reports a data size of 75MB and index size of 300MB
See https://stackoverflow.com/a/1460629
Have a lot of data in the entity usage table
Add a serial field for the primary key and add indexes for the queries in the module.
None
TBD
TBD
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
Comment #3
alexpottHere's a review of all the queries in the module to see how they might be affected.
Deletes
\Drupal\entity_usage\EntityUsage::registerUsage()
This can use the secondary indexes and I think the source and target combination will be enough to ensure that there are not too many rows to filter with the other conditions. This query might be a tiny bit slower but I do think it will be noticeable. There is a chance it will be quicker because the keys will be removed quicker.
\Drupal\entity_usage\EntityUsage::bulkDeleteTargets
Uses the secondary indexes.
\Drupal\entity_usage\EntityUsage::bulkDeleteSources
Uses the secondary indexes.
\Drupal\entity_usage\EntityUsage::deleteByField
Uses the secondary index - could be better but this is unchanged by this issue - also field deletion is not that common.
\Drupal\entity_usage\EntityUsage::deleteBySourceEntity()
Uses the secondard index - could be better - we could consider adding source_langcode and source_vid to the secondary indexes.
\Drupal\entity_usage\EntityUsage::deleteByTargetEntity()
Uses the secondary indexes.
Selects
\Drupal\entity_usage\EntityUsage::listSources()
Uses the secondary index
\Drupal\entity_usage\EntityUsage::listTargets()
Uses the secondary index. Could be better (but existing if we add the vid)
\Drupal\entity_usage\EntityUsage::listTargetEntitiesByFieldAndMethod()
Uses the secondary index - but also could be improved. Not made worse here.
Merge
\Drupal\entity_usage\EntityUsage::registerUsage()
Will use the secondary indexes... this is the 1 query that might be a little worse. But again the smaller index size might also help and source_id_string was not in the primary index so...
There are no updates or upserts to the entity_usage table.
Comment #4
alexpottAnother thing the primary key was doing was providing a uniqueness check. That said it was missing the source_id_string field so it was probably broken a bit in this case. And also the use of the merge in
\Drupal\entity_usage\EntityUsage::registerUsage()ensures the uniqueness - and we don't support any other API of writing to this table and if you do you are responsible for that.Therefore I think this is a good approach and will but the table on a diet!
Comment #5
alexpottRealised that this will require changes to bulk loading as we currently relying on the primary key to not introduce duplicates...
FWIW still testing whether or not this actually improves things. Running on a huge site with over 10 million rows in the entity usage table...
Comment #6
alexpottSo... I've tried this out on a site which has a huge entity usage table (over 10,000,000 rows!)....
Before
Total: 4709.97
After
Total: 2365.72
So this is super interesting... the primary index is basically the same size - I believe the PRIMARY index is just the same as the table data. But as we can see the secondary indexes are way way smaller. So this is definitely worth doing.
So this is a saving of nearly 50%! Definitely seems worth pursuing especially as we need to add another index for #3547273: Deleting paragraphs causes the entity usage tab to display confusing information
Comment #7
alexpottThis issue found an obscure postrgres bug - see #3561800: Using \Drupal\Core\Database\Query\Insert::from() on postgres on a table with a serial field can result in duplicate key error... implemented slightly different way of inserting from the bulk table to the entity_usage table to workaround this but also it might be better anyway as inserting serial IDs into the db is not thread safe...
Comment #8
alexpottMoving to the new branch.
Comment #9
scott_euser commentedWe tried this out on a giant site we a huge amount of content,
Total index size: 5080.00 mbTotal index size: 1451.84 mbAdded a small nitpick re the update hook message being incorrect.
What do you think about post update batch running the recreate? Or potentially version bump in case people miss the update hook message?
(BTW if you are crediting for review, please credit @vitaliyb98 not me as he did the testing on it, but I appreciate we haven't really contributed much here, just taking advantage of your great work, thank you!)
Comment #10
scott_euser commentedBeyond the update hook vs version, + the message nitpick, its RTBC from me
Comment #11
alexpott@scott_euser I don't think we can add the batch recreate to the update - if you put your site into maintenance mode as you should that'd take your site down unnecessarily for hours. And yes this will definitely only go in the next major version of the module.
@scott_euser @vitaliyb98 thank you very very much for testing this and confirming my research. You both definitely will get credit.
I'm going to commit this to the 5.x dev branch as this is a key issue for the 5.0 release that will hopefully happen once we've solved #3547273: Deleting paragraphs causes the entity usage tab to display confusing information
Comment #12
alexpottOne option is we could run the batch update by default but use a setting to allow sites to override if they want. I guess I'm still concerned that this will result in production deployments catching people out and suddenly taking ages. Hard problem. I think on balance the current approach is best but I'm open to ideas!
Comment #13
marcoscanoLet's not batch-regenerate on an update hook, please. The regeneration process should be an intentional action site admins perform when they've tested it on non-prod environments and know how it goes so they can decide when to trigger it (and only this). During DB updates several other things are happening and it doesn't feel right to block all that (which may be critical to the site working) on the usage tables being regenerated (which usually isn't critical).
Thanks for working on this Alex! 🙏
Comment #14
scott_euser commentedThanks! Yeah with major version upgrade it's a lot safer and less likely to get missed I think so I'm happy with it is it is as well, thank you!
Comment #15
berdirThe 5.x update path already requires a reindex, no?
It's only a development release, so presumably very few people would attempt a 5.x -> 5.x update path at this point. I think this is perfectly fine.
Comment #16
alexpott@berdir it doesn't but I was planning on making this change with #3547273: Deleting paragraphs causes the entity usage tab to display confusing information following close behind because both would have required re-indexing. But as it turns out it don;t think that one is going to result in a schema change so this is the single that I plan for 5.x before 5.0.0 that requires re-indexing.
Comment #18
alexpottI've merged this into 5.x