changeset 393:9af6bd45c1f8

Another try at #191 after getting some good advice in a django-users thread.
author Brian Neal <bgneal@gmail.com>
date Thu, 24 Mar 2011 00:15:34 +0000
parents 79240675b903
children 2cb0cc334c50
files gpp/forums/feeds.py gpp/forums/models.py
diffstat 2 files changed, 16 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/gpp/forums/feeds.py	Wed Mar 23 02:02:44 2011 +0000
+++ b/gpp/forums/feeds.py	Thu Mar 24 00:15:34 2011 +0000
@@ -4,8 +4,7 @@
 from django.core.exceptions import ObjectDoesNotExist
 from django.shortcuts import get_object_or_404
 
-from forums.models import Forum
-from forums.models import Post
+from forums.models import Forum, Topic, Post
 from core.functions import copyright_str
 
 
@@ -55,27 +54,24 @@
     def items(self, obj):
         if obj is None:
             # return a combined feed of public forum threads
-            #
-            # This didn't work real well on InnoDb:
-            # items = Post.objects.filter(
-            #         topic__forum__in=Forum.objects.public_forums())
-            #
-            # For some reason, MySQL wasn't using an index when "in" was used.
-            # So let's do this the hard way as a work-around:
 
-            public_forum_ids = Forum.objects.public_forum_ids()
-            posts = []
-            for forum_id in public_forum_ids:
-                posts.extend(list(Post.objects.filter(
-                    topic__forum=forum_id).order_by('-creation_date').select_related(
-                        'topic', 'user', 'topic__forum')[:30]))
+            # This was tricky to do without suffering a large performance
+            # impact. Because the number of forums is small, MySQL did not
+            # try to use an index and ended up searching all the topics for
+            # candidate posts. We work around this first getting a small list
+            # of candidate topics, and then searching them. This is more
+            # queries but a *lot* more time efficient.
 
-            posts.sort(key=lambda x: x.creation_date, reverse=True)
-            return posts[:30]
+            forum_ids = Forum.objects.public_forum_ids()
+            topic_ids = list(Topic.objects.filter(forum__in=forum_ids).order_by(
+                    '-update_date').values_list('id', flat=True)[:30])
+            items = Post.objects.filter(topic__in=topic_ids)
 
         else:
-            return Post.objects.filter(topic__forum__id=obj.id).order_by(
-                '-creation_date').select_related('topic', 'user', 'topic__forum')[:30]
+            items = Post.objects.filter(topic__forum=obj)
+
+        return items.order_by('-creation_date').select_related('topic', 'user',
+                'topic__forum')[:30]
 
     def item_title(self, item):
         return item.topic.name
--- a/gpp/forums/models.py	Wed Mar 23 02:02:44 2011 +0000
+++ b/gpp/forums/models.py	Thu Mar 24 00:15:34 2011 +0000
@@ -202,7 +202,7 @@
 
     # denormalized fields to reduce database hits
     post_count = models.IntegerField(blank=True, default=0)
-    update_date = models.DateTimeField()
+    update_date = models.DateTimeField(db_index=True)
     last_post = models.OneToOneField('Post', blank=True, null=True,
         related_name='parent_topic')