1

これは私のWebアプリケーションではるかに遅いクエリです。

SELECT prof.user_id                      AS userId,
       prof.first_name                   AS first,
       prof.last_name                    AS last,
       prof.birthdate,
       prof.class_string                 AS classes,
       prof.city,
       prof.country,
       prof.state,
       prof.images,
       prof.videos,
       u.username,
       u.avatar,
       (SELECT Count(*)
        FROM   company_member_sponsorship
        WHERE  member_id = prof.user_id
               AND status = 'sponsored') AS sponsor_count,
       (SELECT Count(*)
        FROM   member_schedules
        WHERE  user_id = prof.user_id)   AS sched_count
FROM   member_profiles prof
       LEFT JOIN users u
              ON u.id = prof.user_id
ORDER  BY ( prof.images + prof.videos * 5 + (
            CASE
              WHEN prof.expire_date > :time THEN 50
              ELSE 0
            end ) + sponsor_count * 20 + sched_count * 4
          ) DESC,
          prof.last_name ASC
LIMIT  :start, :records  

すべてのレベルで多くのクエリが発生している場合でも、サイト上の他のすべてのものをロードするのに1秒もかかりません。これは約3〜4秒かかります。

明らかに、速度低下の原因となっているのはテーブルスキャンです。理由は理解できます。最初のテーブルには50,000以上の行があり、2番目のテーブルには160,000以上の行があります。

このクエリを最適化して高速化する方法はありますか?

最悪の場合、私はいつでもコードを調べて、画像やビデオの場合と同じように、プロファイルテーブルでスポンサーシップやイベントの集計を維持できますが、それは避けたいと思います。

編集:EXPLAINの結果をクエリに追加しました。

id  select_type         table                       type    possible_keys   key         key_len ref                         rows    Extra
1   PRIMARY             prof                        ALL     NULL            NULL        NULL    NULL                        44377   Using temporary; Using filesort
1   PRIMARY             u                           eq_ref  PRIMARY         PRIMARY     3       mxsponsor.prof.user_id      1   
3   DEPENDENT SUBQUERY  member_schedules            ref     user_id         user_id     3       mxsponsor.prof.user_id      6       Using index
2   DEPENDENT SUBQUERY  company_member_sponsorship  ref     member_id       member_id   3       mxsponsor.prof.user_id      2       Using where; Using index

EDIT2:

メンバープロファイルのカウントを維持することで問題に対処することになりました。スポンサーシップ/イベントが追加/削除される場合は常に、スポンサーシップ/イベントテーブルをスキャンしてそのメンバーのカウントを更新する関数を呼び出すだけです。このようなクエリを最適化する方法はまだあるかもしれませんが、このサイトはもうすぐ公開されるので、今のところは迅速で汚い解決策を使用します。

4

1 に答える 1

2

動作することは保証されていませんが、内部選択ではなくjoinandを使用してみてください:group by

SELECT prof.user_id      AS userId,
       prof.first_name   AS first,
       prof.last_name    AS last,
       prof.birthdate,
       prof.class_string AS classes,
       prof.city,
       prof.country,
       prof.state,
       prof.images,
       prof.videos,
       u.username,
       u.avatar,
       Count(cms.id)     AS sponsor_count,
       Count(ms.id)      AS sched_count
FROM   member_profiles prof
       LEFT JOIN users u
              ON u.id = prof.user_id
       LEFT JOIN company_member_sponsorship cms
              ON cms.member_id = prof.user_id
                 AND cms.status = 'sponsored'
       LEFT JOIN member_schedules ms
              ON ms.user_id = prof.user_id
GROUP  BY u.id
ORDER  BY ( prof.images + prof.videos * 5 + (
            CASE
              WHEN prof.expire_date > :time THEN 50
              ELSE 0
            end ) + sponsor_count * 20 + sched_count * 4
          ) DESC,
          prof.last_name ASC
LIMIT  :start, :records  

それが良くない場合はexplain、そのクエリの a が役立ちます。

于 2012-07-07T01:46:24.220 に答える