2012-02-29 17 views
0

「ソーシャルネットワーク」のようにサイトに新しい機能を実装しました。djangoクエリを最適化する

ユーザーが行ったり、メッセージやものを受け取るさまざまなアクション。彼らの友達はすべての行動を見ることができます。

class userMuralEntry(models.Model): 
    user_src = models.ForeignKey(userInfo, related_name="user_src") 
    user = models.ManyToManyField(userInfo, related_name="user_dest") 
    user_follow = models.ManyToManyField(userInfo, related_name="user_follow") 
    private = models.BooleanField(default=False) 
    content = models.TextField() 
    date = models.DateTimeField(default=datetime.now) 
    last_update = models.DateTimeField() 

    object_type = models.ForeignKey(muralType) 

    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey('content_type', 'object_id') 

私は自分のフロントページにアクセスするたびに、プライベートなものを除くすべての私の友人の行動を得ます。 だから、私は(Explain出力とここ)このBIGクエリを生成し、このDjangoのモデルは

mural_list = db.userMuralEntry.objects.filter(Q(user__pk__in=friend_list)|Q(user_src__pk__in=friend_list)).order_by('-last_update') 
    m = mural_list.exclude(
    Q(private=True), 
    ~Q(user_src=me_db) & ~Q(user=me_db)) 

    m = m.distinct() 

を照会し、すべてのコードを作っ

SELECT DISTINCT myps3t_usermuralentry.id, 
       myps3t_usermuralentry.user_src_id, 
       myps3t_usermuralentry.private, 
       myps3t_usermuralentry.content, 
       myps3t_usermuralentry.DATE, 
       myps3t_usermuralentry.last_update, 
       myps3t_usermuralentry.object_type_id, 
       myps3t_usermuralentry.content_type_id, 
       myps3t_usermuralentry.object_id 
FROM myps3t_usermuralentry 
     LEFT OUTER JOIN myps3t_usermuralentry_user 
     ON (myps3t_usermuralentry.id = 
       myps3t_usermuralentry_user.usermuralentry_id) 
     LEFT OUTER JOIN myps3t_userinfo t4 
     ON (myps3t_usermuralentry.user_src_id = t4.id) 
WHERE ((myps3t_usermuralentry_user.userinfo_id = 20877 
      OR myps3t_usermuralentry.user_src_id = 20877) 
     AND NOT (myps3t_usermuralentry.private = 1 
        AND (NOT ((t4.id = 21095 
           AND NOT (t4.id IS NULL))) 
         AND NOT (myps3t_usermuralentry.id IN 
            (SELECT u1.usermuralentry_id 
            FROM 
            myps3t_usermuralentry_user u1 
                   WHERE ( 
            u1.userinfo_id = 
            21095 
            AND 
            u1.usermuralentry_id 
            IS 
            NOT 
            NULL 
                     ))))) 
     ) 
ORDER BY myps3t_usermuralentry.last_update; 



mysql> explain SELECT DISTINCT `myps3t_usermuralentry`.`id`, `myps3t_usermuralentry`.`user_src_id`, `myps3t_usermuralentry`.`private`, `myps3t_usermuralentry`.`content`, `myps3t_usermuralentry`.`date`, `myps3t_usermuralentry`.`last_update`, `myps3t_usermuralentry`.`object_type_id`, `myps3t_usermuralentry`.`content_type_id`, `myps3t_usermuralentry`.`object_id` FROM `myps3t_usermuralentry` LEFT OUTER JOIN `myps3t_usermuralentry_user` ON (`myps3t_usermuralentry`.`id` = `myps3t_usermuralentry_user`.`usermuralentry_id`) LEFT OUTER JOIN `myps3t_userinfo` T4 ON (`myps3t_usermuralentry`.`user_src_id` = T4.`id`) WHERE ((`myps3t_usermuralentry_user`.`userinfo_id` = 20877 OR `myps3t_usermuralentry`.`user_src_id` = 20877) AND NOT (`myps3t_usermuralentry`.`private` = 1 AND (NOT ((T4.`id` = 21095 AND NOT (T4.`id` IS NULL))) AND NOT (`myps3t_usermuralentry`.`id` IN (SELECT U1.`usermuralentry_id` FROM `myps3t_usermuralentry_user` U1 WHERE (U1.`userinfo_id` = 21095 AND U1.`usermuralentry_id` IS NOT NULL)))))) ORDER BY `myps3t_usermuralentry`.`last_update` DESC LIMIT 20; 
+----+--------------------+----------------------------+-----------------+-------------------------------------------------------------------------------------------+-------------------+---------+---------------------------------------------------+--------+------------------------------------+ 
| id | select_type  | table      | type   | possible_keys                    | key    | key_len | ref            | rows | Extra        | 
+----+--------------------+----------------------------+-----------------+-------------------------------------------------------------------------------------------+-------------------+---------+---------------------------------------------------+--------+------------------------------------+ 
| 1 | PRIMARY   | myps3t_usermuralentry  | ALL    | myps3t_usermuralentry_99bd10ae               | NULL    | NULL | NULL            | 665410 | Using temporary; Using filesort | 
| 1 | PRIMARY   | myps3t_usermuralentry_user | ref    | usermuralentry_id,myps3t_usermuralentry_user_bcd7114e          | usermuralentry_id | 4  | fabriciols_ps3t.myps3t_usermuralentry.id   |  2 | Using where; Using index; Distinct | 
| 1 | PRIMARY   | T4       | eq_ref   | PRIMARY                     | PRIMARY   | 4  | fabriciols_ps3t.myps3t_usermuralentry.user_src_id |  1 | Using where; Using index; Distinct | 
| 2 | DEPENDENT SUBQUERY | U1       | unique_subquery | usermuralentry_id,myps3t_usermuralentry_user_bcd7114e,myps3t_usermuralentry_user_6b192ca7 | usermuralentry_id | 8  | func,const          |  1 | Using index; Using where   | 
+----+--------------------+----------------------------+-----------------+-------------------------------------------------------------------------------------------+-------------------+---------+---------------------------------------------------+--------+------------------------------------+ 
4 rows in set (0.00 sec) 

mysql> show indexes from myps3t_usermuralentry ; 
+-----------------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table     | Non_unique | Key_name      | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+-----------------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+ 
| myps3t_usermuralentry |   0 | PRIMARY      |   1 | id    | A   |  665410 |  NULL | NULL |  | BTREE  |   | 
| myps3t_usermuralentry |   1 | myps3t_usermuralentry_99bd10ae |   1 | user_src_id  | A   |  22180 |  NULL | NULL |  | BTREE  |   | 
| myps3t_usermuralentry |   1 | myps3t_usermuralentry_ae71a55b |   1 | object_type_id | A   |   8 |  NULL | NULL |  | BTREE  |   | 
| myps3t_usermuralentry |   1 | myps3t_usermuralentry_e4470c6e |   1 | content_type_id | A   |   13 |  NULL | NULL |  | BTREE  |   | 
+-----------------------+------------+--------------------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+ 
6 rows in set (0.00 sec) 

私はインデックスにいくつかの微調整をしたが、そのあまりにも遅いです。 3〜4人の友人を持つユーザーは5秒のようになります!

この表には現在500,000行あります。

改善のアイデアですか?私のジャンゴコードは乱雑ですか?私の手で質問をするのが最善でしょうか?

+0

なぜ代わりにフィルタを連鎖のQオブジェクトのすべて、/呼び出しを除外? – Marcin

+0

beacause私はOR操作が必要です...(ユーザーOR user_src)Qオブジェクトなしで行う方法はありますか? – fabriciols

+0

あなたの除外はおそらく単純化できます。 – Marcin

答えて

2

あなたは再びこれを読んでする必要があります。https://docs.djangoproject.com/en/dev/topics/db/queries/

あなたのコードを簡素化することができますいくつかの方法があります。たとえば:

mural_list = db.userMuralEntry.objects.filter(Q(user__pk__in=friend_list)|Q(user_src__pk__in=friend_list)) 

は同等です:

mural_list = db.userMuralEntry.objects.filter(user__pk__in=friend_list)|db.userMuralEntry.objects.filter(user_src__pk__in=friend_list) 

m = mural_list.exclude(
    Q(private=True), 
    ~Q(user_src=me_db) & ~Q(user=me_db)) 

は、でORDER_BY句を置くことはおそらく優れていることを

m = mural_list.exclude(private=True).exclude(user_src=me_db).exclude(user=me_db) 

注意に相当します終了、外部結合を避けるためにordered_byクエリで

最終最適化されたSQLは、親切に、ここで@fabriciolsによって共有されました:http://chat.stackoverflow.com/transcript/message/2795524#2795524