Closed (fixed)
Project:
Flag Friend
Version:
6.x-1.x-dev
Component:
Code
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
30 Jun 2009 at 16:53 UTC
Updated:
12 Aug 2009 at 03:40 UTC
Jump to comment: Most recent file
Comments
Comment #1
sirkitree commentedThe flag_content table is used up until there is a friendship created. As soon as your flag is approved by another user, in which they also flag you, there are now two flags within flag_content. At this point we record the relationship within the flag_friend table and then completely remove both entries from the flag_content table.
Comment #2
pcambraThanks for the answer.
Wouldn't make faster queries to duplicate this information in flag_friend table? I mean if uid 2 adds uid 3, then having two records will make the queries only to look up for uid and not for both uid and friend_uid.
By the way, what is the difference between FLAG_FRIEND_BOTH and FLAG_FRIEND_FLAGGED status?
Comment #3
sirkitree commentedI try to follow the DRY principle as much as possible: Don't Repeat Yourself - but have gone against it in cases of performance occasionally. I'm not sure how much it would speed it up really so if you can answer that we can go from there.
The difference between FLAG_FRIEND_BOTH and FLAG_FRIEND_FLAGGED:
FLAG_FRIEND_BOTH is set when both users are flagged.
FLAG_FRIEND_FLAGGED is set when both users are in the flag_friend table.
As soon as FLAG_FRIEND_BOTH is detected within hook_flag(), the flags are removed and the entry created in the flag_friend table thus making the next status detection FLAG_FRIEND_FLAGGED. So no other module should ever really be able to detect FLAG_FRIEND_BOTH.
Comment #4
Scott Reynolds commentedI believe the goal of this table structure is to keep the table size small while still providing all the functionality.
This is a sacrifice of query speed for table size.
Comment #5
pcambraI see, you are right with the table size, records will be always twice, maybe it could be exposed somewhere as an option because the OR condition damages performance, I think.
So, if I need to check in my module if two users are friends with each other, I should check for FLAG_FRIEND_FLAGGED and NOT for FLAG_FRIEND_BOTH. Is that correct?
Comment #6
sirkitree commentedCorrect
Comment #7
markus_petrux commentedPlease, let me re-open for consideration...
Here's a couple of tricks that can be used to optimize these queries:
1) Use 2 queries with UNION ALL, a query for each OR condition.
2) Use 2 separate statements. This can be used in DELETE operations, for example, making them faster as each one will use index.
Comment #8
sirkitree commentedOk, let 's mark this issue as such then.
Comment #9
markus_petrux commentedWell, here's a patch that tries to optimize this a little.
1) Adds an additional index to {flag_friend} table by friend_uid column. This index allows MySQL (since 5.0) optimize certain queries with index_merge access type.
2) Fixes a bug in DELETE FROM {flag_friend}, and then the query itself is also optimized by the new index.
This is how MySQL will resolve the queries:
Case 1:
MySQL uses here the primary key using the range access method to resolve each OR condition. Both queries were working ok to date, and they are not affected by the attached patch.
Case 2:
MySQL 5.0+ will use here index_merge. That means it will be able to use the primary key and the newly added index to resolve each condition, and then merge the results.
This one is fixed like this:
And now, the WHERE clause is exactly the same as the SELECT, so it can benefit from the same performance optimization.
More information about MySQL Index Merge Optimization:
http://dev.mysql.com/doc/refman/5.0/en/index-merge-optimization.html
http://dev.mysql.com/doc/refman/5.1/en/index-merge-optimization.html
PostgreSQL also supports multiple indexes per query.
PS: My comment in #7 was based on the method that was necessary prior to this performance optimization (Index Merge) introduced in MySQL 5.
Comment #10
pcambraHi
I've added a function for getting the number of friends of a given user (see #524966: Integration of flag_friend with panels) and the explain seems to benefit of the patch suggested by markus_petrus:
This is the query
SELECT COUNT(1) FROM {flag_friend} WHERE uid = %d OR friend_uid = %dThese are the explains:
Without the index:
With the index:
Comment #11
markus_petrux commented@pcambra: with the new index, in the column 'type' you should see 'index_merge', and in the column 'extra', you should see 'Using union(PRIMARY,friend_uid); Using where'.
Are you testing on MySQL 5.0+? If so, then it might be possible that the index_merge optimization is discarded if your {flag_friend} table doesn't have many rows.
If you insert more rows for testing, you may also wish to run
OPTIMIZE TABLE {flag_friend}so that the internal table statistics are updated for the MySQL optimizer to take the right decision.Comment #12
pcambraRight, I've tested with 10 thousand records in flag_friend table and results have more sense:
Comment #13
sirkitree commentedWow guys, thanks for the in depth explanations, examples and patch! I learned a lot in this thread. Comitted: http://drupal.org/cvs?commit=244194