Problem/Motivation
SearchApiTagCache::getRowId is a very expensive function, that can slow down views a lot.
It's doesn't have its own implementation, it uses the parent method CachePluginBase::getRowId.
In CachePluginBase::getRowId all entity objects in 'index', '_entity', '_relationship_entities' are removed, because serializing objects is expensive.
For search_api the objects are not stored in those keys. Search api has its own keys. '_item', '_object', '_relationship_objects' and 'entity:node/_object'.
That means serializing a search api row result includes all the entity objects.
Proposed resolution
Remove the _item', '_object', '_relationship_objects', 'entity:node/_object' keys before serializing the row.
Comments
Comment #2
chr.fritschHere is a patch.
It improved the views loading time from 1.2 sec to 0.7 sec for me.
Comment #3
legolasboYour suggested change makes sense and looks good to me. I only have one nitpick, but that can be fixed on commit.
This line is getting pretty long. Maybe extract the array_flip(...) bit into a variable to improve readability?
Comment #4
drunken monkeyThanks a lot for the patch, good suggestion!
However, it seems excluding
$row->search_api_datasource . '/_object'specifically isn’t enough, as other such properties can contain entities as well (e.g., in my case,$row->{'entity:node/type:_object'}). So probably we need a more advanced solution here, going throw the whole(array) $rowarray and unsetting all search items, entities and (probably also?) entity wrappers. Or maybe we can replace them with a unique string, likeentity::node::123, just to be on the safe side? If we’re already adding a helper method to go through all properties (recursively, I guess), this shouldn‘t be much extra work. (I’m not at all certain our cache tags are adequate, that’s the problem here, so better be on the safe side regarding the properties, I’d say.)Comment #5
chr.fritschI simplified the code to just return the search_api_id as cache row id.
I also found out, that the row cache tags are not set properly.
Comment #7
chr.fritschA new patch to fix the failing tests
Comment #8
drunken monkeyHm, OK, I guess that could work. Not sure, though, don’t understand caching (especially for Views) well enough. Would be great to have others confirm this makes sense and works for them (or looks to them like it should work).
In any case, though,
$row->_relationship_objectsalready contains$row->_object, so we can simplify a bit. (Otherwise, we’d have to verify that this is an entity, too.)In any case, this change looks like it would break things for indexes that contain non-entities – but since that’s a rather minor use case, and the problems should not be large (just potentially showing stale data until item is re-indexed), I think we can live with that compared to the large performance gain for the main use case.
Comment #9
drunken monkeyAlso, is there a simple way to get this covered by tests, do you think?
Comment #10
chr.fritschI think getRowCacheTags is kind of covered by ViewsDisplayCachingTest. For getRowId we could look at RowRenderCacheTest::testNoCaching and try to build a similar test.
Comment #12
drunken monkeyAlright, that’s probably not worth it.
So, let’s just commit this.
Thanks again, everyone!