When flags are used as part of a views relationship the resulting query performance slows as more and more flag content is introduced. This issue arouse as part of how the message subscribe module uses flagging on content and provides a way to view all flagged content you have subscribed to.
The following is the query and explain output for before and after the attached patch.
EXPLAIN SELECT COUNT(*) AS expression FROM (SELECT 1 AS expression FROM node_field_data node_field_data INNER JOIN flagging flagging_node_field_data ON node_field_data.nid = flagging_node_field_data.flagged_entity__target_id_int AND flagging_node_field_data.flag_id = 'subscribe_node' LEFT JOIN flagging flagging_node_field_data_1 ON node_field_data.nid = flagging_node_field_data_1.flagged_entity__target_id_int AND (flagging_node_field_data_1.flag_id = 'email_node' AND flagging_node_field_data_1.uid = '254') WHERE (( (flagging_node_field_data.uid = '254' ) )) subquery;
+----+--------------------+----------------------------+------+----------------------------------------------------------------+--------------------------------+---------+-----------------------------------------
| id | select_type | table | type | possible_keys | key | key_len | ref
+----+--------------------+----------------------------+------+----------------------------------------------------------------+--------------------------------+---------+-----------------------------------------
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL
| 2 | DERIVED | flagging_node_field_data | ref | flagging_field__uid__target_id | flagging_field__uid__target_id | 4 | const
| 2 | DERIVED | node_field_data | ref | PRIMARY,node__id__default_langcode__langcode,node__status_type | PRIMARY | 4 | community_dev.flagging_node_field_data.f
| 2 | DERIVED | flagging_node_field_data_1 | ref | flagging_field__uid__target_id | flagging_field__uid__target_id | 4 | const
| 3 | DEPENDENT SUBQUERY | na | ref | PRIMARY | PRIMARY | 4 | community_dev.node_field_data.nid
+----+--------------------+----------------------------+------+----------------------------------------------------------------+--------------------------------+---------+-----------------------------------------
(END)
although it is defaulting to an index query times still range from 45-50 seconds for 4800 return values.
After adding an index on uid, flag_id, flagged_entity__target_id_int
the average query time is about _.085 seconds_
+----+--------------------+----------------------------+------+-----------------------------------------------------------------------------------+----------------------------------------------------+---------+--
| id | select_type | table | type | possible_keys | key | key_len | r
+----+--------------------+----------------------------+------+-----------------------------------------------------------------------------------+----------------------------------------------------+---------+--
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | N
| 2 | DERIVED | flagging_node_field_data | ref | flagging_field__uid__target_id,flagging_flag_id_uid_flagged_entity__target_id_int | flagging_flag_id_uid_flagged_entity__target_id_int | 770 | c
| 2 | DERIVED | node_field_data | ref | PRIMARY,node__id__default_langcode__langcode,node__status_type | PRIMARY | 4 | c
| 2 | DERIVED | flagging_node_field_data_1 | ref | flagging_field__uid__target_id,flagging_flag_id_uid_flagged_entity__target_id_int | flagging_flag_id_uid_flagged_entity__target_id_int | 775 | c
| 3 | DEPENDENT SUBQUERY | na | ref | PRIMARY | PRIMARY | 4 | c
+----+--------------------+----------------------------+------+-----------------------------------------------------------------------------------+----------------------------------------------------+---------+--
The performance for the selection of data mimics this performance gain with query times around .11-.13 seconds.
Comment | File | Size | Author |
---|---|---|---|
#41 | flagging_views_index-2888664-41.patch | 2.45 KB | pascalim |
#39 | flagging_views_index-2888664-39.patch | 1.43 KB | mediabounds |
#36 | flag-2888664-36.patch | 2.65 KB | mvogel |
#12 | new_index_for_flagging-2888664-12.patch | 1.42 KB | sylus |
#8 | flagging_views_index-2888664-8.patch | 1.26 KB | ndrake86 |
Comments
Comment #2
ndrake86 CreditAttribution: ndrake86 at Workday, Inc. commentedAttaching patch.
Comment #4
ndrake86 CreditAttribution: ndrake86 at Workday, Inc. commentedRealized this patch really doesn't make sense until https://www.drupal.org/node/2678756 lands since there is a schema change.
Comment #5
ndrake86 CreditAttribution: ndrake86 at Workday, Inc. commentedUploading a patch that will work once https://www.drupal.org/node/2678756 gets committed. There is still a valid index that can be applied before 2678756 which is basically the same just using but just uses the integer entity ID field but for my use case adding flagging for content views is important.
Comment #6
socketwench CreditAttribution: socketwench commentedThank you for both patches! Right now I'm not sure if the config entity patch will get in, so I'm inclined to get the first patch in and add the indexing to the patch in the config entity issue.
Comment #7
ndrake86 CreditAttribution: ndrake86 at Workday, Inc. commentedDefinitely understand. Let me do a cleaner patch that doesn't take into account the content entity stuff.
Comment #8
ndrake86 CreditAttribution: ndrake86 at Workday, Inc. commentedAttached is a patch for the current dev branch, not just for the content entity flagging.
Comment #10
martin107 CreditAttribution: martin107 as a volunteer commentedI am not an expert in this area,
so I want to talk this through ... I suspect different parts of this will be obvious to each reader and if we put our heads together then we can make progress.. I will do any legs work regarding research and patch making.
Do I read that correctly ....
In addition to our definition of the "flag config entity" in flag.schema we also need to add definitions in flag.install flag_schema()?
I will keep this at needs review but as a note to myself when I come back to make the next patch we currently use array() when [] is preferred.
Comment #11
sylus CreditAttribution: sylus commentedI'm curious about the above as well as have been unable to workaround this.
Comment #12
sylus CreditAttribution: sylus commentedI needed a quick workaround as was unsure how to solve this via
/src/Entity/Storage/FlaggingStorageSchema.php
. I just leveraged hook_install + hook_update_n.Comment #14
myke CreditAttribution: myke commented(I have a site running on Drupal 7 that had Views involving flags get extremely slow. I added an index to uid and a query that was taking 60 seconds to complete now takes less than .1 seconds. I believe it may be related to this issue in Drupal 8's Flags module. Glad to see it being addressed before I upgrade.)
Comment #15
KlemenDEV CreditAttribution: KlemenDEV as a volunteer and at Pylo commentedI can confirm this. We have a website with views counting flag count using aggregation and the performance of these pages is very bad.
Comment #16
dureaghin CreditAttribution: dureaghin commentedI can confirm this too. We have a flagging table with +500.000 records and it's super slow 2-3 minutes query execution time.
I checked duplicate indexes using "pt-duplicate-key-checker", and I found this:
Removing this index does not help.
Comment #17
parkout CreditAttribution: parkout commentedI can confirm too. Loading page about 2-3 minutes. With 5000 node + . Why anybody cant find a way to repair it? flag not working for drupal 8 correctly =(
Comment #18
acrollet CreditAttribution: acrollet commentedre-roll
Comment #19
parkout CreditAttribution: parkout commentedDid not help.
I have cleared my flagging table. And its start working faster (because table just cleaned) . But loading page with flags takes about 6 seconds. And this page without flags takes about 2 sec.
How to make it work faster?
Comment #20
brunodboThis is a reroll of #8.
Re:10: It looks like
$schema->addIndex($table, $name, $fields, $spec)
expects the full table specification as the fourth argument (see https://www.drupal.org/project/drupal/issues/2537928). Attached patch adds the full spec, we'll see what testbot says.Adding this index allowed me to sort a node view on flagging count (43,617 nodes, 145,824 flaggings in my db), as long as the view uses flaggings by the current user in the relationship:
Query build time: 17.38 ms
Query execute time: 35.86 ms
View render time: 74.69 ms
If I configure the flagging relationship to show flaggings by any user (which is what I need), the preview in Views never even gets rendered, and the query just seems to hang (same behaviour as without the patch).
Comment #22
brunodboAfter playing around with the view some more, it seems that it's the 'Sort by flagging count' that's causing this to become very slow.
Comment #23
KlemenDEV CreditAttribution: KlemenDEV as a volunteer and at Pylo commentedEven views without 'Sort by flagging count' just showing the flagging count as a field can be very slow with large amount of nodes and flags on them.
Comment #24
parkout CreditAttribution: parkout commentedThe main problem is the relations of the flag. If you remove this, then everything loads quickly. In node specific page, but without relationship. it works fast there. But on the pages of terms it takes a very long time to load. Loads quickly only if the person is logged in
And i have not sort by flag, and still have performance problem for anonymous users
Comment #25
parkout CreditAttribution: parkout commentedPlease help with this problem( Flag module normally works only for authed users.
Comment #26
slogar32 CreditAttribution: slogar32 at Agiledrop - Your Trusted Drupal Teammates commentedFixed the FlaggingStorageSchema index array definition.
Comment #27
parkout CreditAttribution: parkout commentedIt did not help. If there are a lot of nodes, the site slows down a lot. Or the database crashes altogether
Comment #28
sashken2 CreditAttribution: sashken2 commentedI have same problem too if I use Flags as Relations in my views. Site works very slow. If delete Flags from Relations - site works very fast. But I need this relation for 'Sort by flagging count'
Comment #29
sashken2 CreditAttribution: sashken2 commentedPatch #26 works good for new install module Flag (patched #26).
But if I using patch for existing flagging entities. I have error. I can't update flagging entities. I use module https://www.drupal.org/project/entity_update but it don't work.
Comment #30
andyg5000I'm having issues with views relationships and the query using the wrong index as well. The query that views generates is taking > 6 seconds to execute. Adding FORCE INDEX (PRIMARY) after the first INNER JOIN of flagging table fixes this. Adding the index in the patch above does not.
I guess I'm going to try https://www.drupal.org/project/views_index_hint, but would like to hear what others do to resolve this!
Associated EXPLAIN
Comment #31
andyg5000As a follow up to my last comment, we've ended up converting the schema for `entity_id` in the flagging table to an integer column. We also added an index for flag_id and entity_id.
I realize this may cause issues for others including those wanting to flag config entities that have non-numeric ids. For us, it dropped our query time from 35 seconds to 0.035 ms.
Comment #32
KlemenDEV CreditAttribution: KlemenDEV as a volunteer and at Pylo commentedThat is very drastic. Maybe this module should add option for core entities that are known to have numeric ids to offer numeric id in flagging table too, some UI parameter maybe?
Comment #33
mvogel CreditAttribution: mvogel commented@andyg5000
Woah thx for this catch. I also changed the type for 'entity_id' to int and query execution time dropped from about 5 seconds to ~0.0xx seconds.
Comment #34
KlemenDEV CreditAttribution: KlemenDEV as a volunteer and at Pylo commentedComment #35
demon326 CreditAttribution: demon326 commentedCould somebody create a new patch with the latest suggestions and or fixes? The last one is from about a year ago and at least one person reported that is only works on fresh installs.
Where using the flag module on many places and I'd be happy if i could apply a patch that works on existing installs :)
Comment #36
mvogel CreditAttribution: mvogel commentedI created a patch, which should be working for new installs and has an update hook (drush updb) that fixes existing installs.
Be aware that changing the column type could have drawbacks if something expects this column to be a string but it is now an integer. I tested it for my projects and it works fine. I think it will be ok for most cases because the entity_id in drupal is always an integer.
Comment #37
demon326 CreditAttribution: demon326 commented@mvogel , thanks for taking your time to create a patch. I applied it and it seems that everthing still works as expected. Still getting dupe results, but thats a core bug :)
Comment #38
mediabounds CreditAttribution: mediabounds at Float commentedThis is an updated version of the patch from #26 that correctly updates the entity definition so there is no error in the site status report about outdated field definitions.
(To be clear: this patch merely adds the missing index; it does not change the column type.)
Comment #39
mediabounds CreditAttribution: mediabounds at Float commentedAdds a missing import from #38.
Comment #40
igork96 CreditAttribution: igork96 at Agiledrop - Your Trusted Drupal Teammates commentedI tested the patch from #36 and can confirm that it's working.
Comment #41
pascalim CreditAttribution: pascalim at Unipro Ltd commentedAn unspoken rule in Drupal is that
entity_id
columns have always been numeric. Adding more indexes will not help much if those indexes are not getting hit from the datatypes being different. I tested patch #36 and it works fine. Here is an updated patch #36 with the proper patch context.Comment #43
huzookaComment #44
scambler CreditAttribution: scambler at One Young World commented#41 worked for me, thanks.
Comment #45
jackfoust CreditAttribution: jackfoust as a volunteer and at Muni-Link commentedThis is night and day with my Views with flag attached. Is this production ready?