digitalpoint
Well-known member
The XenForo_Model_Thread::prepareThreadFetchOptions() method has some less than ideal joins and calculations going on...
INNER JOINs are noticeably slower than LEFT JOINs (because they need to actually be looked at for exclusions). This gets *really* slow when you have a forum with hundreds (or thousands) of pages of threads... All the threads from previous pages need to actually perform the join in order to see if they are to be excluded from the list.
In the case of this method, the INNER JOINs are really serving no purpose other than to do a double check on data integrity (don't show threads unless the node exists, don't show threads unless the forum exists, don't show the thread unless it has a first post, etc) Doing data integrity checks at the query level is really not worth the huge amount of resources needed when you start getting into high page numbers.
The other issue in this method is SQL IF() statements are even more resource intensive than the JOINs because they also need to be evaluated for all threads in previous pages. This part in particular:
I've modified the method so all the INNER JOINs are LEFT JOINs and changed the above IF() to just return the count regardless if it's NULL or not by changing it to this:
Doing this made the query to get threads in a forum at a very high page number go from 4-5 MINUTES to 2-3 seconds with no noticeable ill effects. The JOINS are just data integrity JOINs that really should never happen... and if something WAS wrong with a thread, wouldn't you want to know/see it? The user_post_count is used for hovering over the small avatar, and it works the same after the change.
INNER JOINs are noticeably slower than LEFT JOINs (because they need to actually be looked at for exclusions). This gets *really* slow when you have a forum with hundreds (or thousands) of pages of threads... All the threads from previous pages need to actually perform the join in order to see if they are to be excluded from the list.
In the case of this method, the INNER JOINs are really serving no purpose other than to do a double check on data integrity (don't show threads unless the node exists, don't show threads unless the forum exists, don't show the thread unless it has a first post, etc) Doing data integrity checks at the query level is really not worth the huge amount of resources needed when you start getting into high page numbers.
The other issue in this method is SQL IF() statements are even more resource intensive than the JOINs because they also need to be evaluated for all threads in previous pages. This part in particular:
Code:
IF(thread_user_post.user_id IS NULL, 0, thread_user_post.post_count) AS user_post_count
I've modified the method so all the INNER JOINs are LEFT JOINs and changed the above IF() to just return the count regardless if it's NULL or not by changing it to this:
Code:
thread_user_post.post_count AS user_post_count
Doing this made the query to get threads in a forum at a very high page number go from 4-5 MINUTES to 2-3 seconds with no noticeable ill effects. The JOINS are just data integrity JOINs that really should never happen... and if something WAS wrong with a thread, wouldn't you want to know/see it? The user_post_count is used for hovering over the small avatar, and it works the same after the change.