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  

即使在各个级别发生大量查询,站点上的所有其他内容也只需不到一秒的时间即可加载。这大约需要 3-4 秒。

显然是表扫描导致了减速。我能理解为什么;第一个表有 50,000+ 行,第二个表有 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

编辑2:

我最终通过在会员资料中维护计数来解决这个问题。无论在哪里添加/删除赞助/活动,我只需调用一个扫描赞助/活动表并更新该成员计数的函数。可能还有一种方法可以优化这样的查询,但是我们很快就会发布这个网站,所以我现在要使用快速而肮脏的解决方案。

4

1 回答 1

2

不保证有效,但尝试使用joinandgroup 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该查询会有所帮助。

于 2012-07-07T01:46:24.220 回答