0

我有以下 mySQL 查询,由于 count / avg 函数和 GROUP BY 需要 26 秒(这在分组表中没有任何记录:gemrating)。如果没有查询的 GROUP BY 部分,则需要 0.1293 秒。有没有办法(例如临时表)来加快速度?我知道一种选择是将总和/计数/平均信息保存在主表中 - 但前提是我必须这样做。除了用户可以选择的 SUM(rating) 中的 sum_rating 字段外,所有连接的 (and ORDER BYand ) 字段都被索引为主键。WHERE

一些概述:gems 是一个帖子和回复表。为了选择带有回复的帖子,我将其连接到自身。但这需要用户和 gemdetail(附件)一次加入帖子(g),一次加入回复(r)。

我在使用 php 的共享服务器上。我以前没有使用过临时表,所以可以使用一些指导或示例。我也乐于听到其他方法来解决有这么多的加入......在此先感谢。

已解决见下文

    SELECT g.gemid as ggemid, g.title as gtitle, g.descr, g.userid as guserid, gemdetail.filename, g.dateentered as gdateentered, g.post, g.sort as gsort, g.grade as ggrade, g.page as gpage, g.page2 as gpage2, g.tab as gtab, concat(users.firstname,' ',users.lastname) AS gfullname, r.gemid as rgemid, r.title as rtitle, r.descr as rdescr, r.userid as ruserid, r.filename as rfilename, r.dateentered as rdateentered, r.post as rpost, r.sort as rsort, r.fullname as rfullname, rt.sum_rating as gsum_rating, rt.ave_experience as gave_experience, rt.count_experience as gcount_experience, rt.count_comments as gcount_comments 
FROM gems g 
LEFT JOIN users ON g.userid = users.userid  
LEFT JOIN gemdetail ON g.gemid = gemdetail.gemid  
LEFT JOIN (

    SELECT title, g2.gemid, g2.replygemid, g2.descr, g2.userid, g2.dateentered, g2.post, g2.sort, gd.filename, concat(users.firstname,' ',users.lastname) AS fullname FROM gems g2  
LEFT JOIN gemdetail gd ON g2.gemid = gd.gemid  
LEFT JOIN users ON g2.userid = users.userid ) r ON g.gemid = r.replygemid  
INNER JOIN ( 
    SELECT gemrating.gemid, avg(experience) as ave_experience, SUM(rating) as sum_rating, COUNT(experience) as count_experience, COUNT(comments) as count_comments FROM gems  
    LEFT JOIN gemrating ON gems.gemid = gemrating.gemid 
    WHERE ISNULL(replygemid) AND gems.tab =0 AND gems.grade = '8' AND gems.page='physics' AND gems.page2='hydraulics'  
    GROUP BY gemrating.gemid  
    ORDER BY gems.sort asc, gemrating.gemid LIMIT 0, 25) rt ON g.gemid = rt.gemid
WHERE ISNULL(g.replygemid) AND g.tab =0 AND g.grade = '8' AND g.page='physics' AND g.page2='hydraulics'     
ORDER BY gsort asc, ggemid, rsort, filename


NOTE: Just Key fields
  PRIMARY KEY (`gemid`),
  KEY `userid` (`userid`),
  KEY `grade` (`grade`(4)),
  KEY `page` (`page`),
  KEY `page2` (`page2`),
  KEY `title` (`title`(50)),
  KEY `sort` (`sort`),
  KEY `tab` (`tab`),
  KEY `descr` (`descr`(255)),
  KEY `replygemid` (`replygemid`),
  KEY `replygemid_2` (`replygemid`)


gemdetail;
+--------------+--------------+------+-----+----------------+
| Field        | Type         | Null | Key | Extra          |
+--------------+--------------+------+-----+----------------+
| gemdetailid  | int(10)      | NO   | PRI | auto_increment |
| gemid        | int(10)      | NO   | MUL |                |
| filename     | varchar(100) | YES  | MUL |                |
+--------------+--------------+------+-----+----------------+

gemrating;
+----------------+--------------+------+-----+-----------------+
| Field          | Type         | Null | Key | Extra           |
+----------------+--------------+------+-----+-----------------+
| gemratingid    | int(10)      | NO   | PRI | auto_increment  |
| gemid          | int(10)      | NO   | MUL |                 |
| rating         | tinyint(4)   | YES  |     |                 |
| userid         | int(10)      | NO   | MUL |                 |
+----------------+--------------+------+-----+------------------

users;
+-------------------+--------------+------+-----+----------------+
| Field             | Type         | Null | Key | Extra          |
+-------------------+--------------+------+-----+----------------+
| userid            | int(10)      | NO   | PRI | auto_increment |
| firstname         | varchar(50)  | NO   |     |                |
| lastname          | varchar(50)  | NO   |     |                | 
+-------------------+--------------+------+-----+----------------+

解释

Profiling
StatusDocumentation     Time
Starting    82 µs
Waiting For Query Cache Lock    22 µs
Checking Query Cache For Query  222 µs
Checking Permissions    22 µs
Checking Permissions    16 µs
Checking Permissions    16 µs
Checking Permissions    16 µs
Checking Permissions    16 µs
Checking Permissions    16 µs
Checking Permissions    16 µs
Checking Permissions    16 µs
Checking Permissions    18 µs
Opening Tables  58 µs
System Lock     199 µs
Optimizing  23 µs
Statistics  28 µs
Preparing   25 µs
Executing   20 µs
Sorting Result  17 µs
Sending Data    108 µs
Optimizing  33 µs
Statistics  96 µs
Preparing   33 µs
Creating Tmp Table  57 µs
Executing   20 µs
Copying To Tmp Table    553 µs
Sorting Result  72 µs
Sending Data    195 µs
Optimizing  22 µs
Statistics  38 µs
Preparing   22 µs
Executing   17 µs
Sending Data    6 ms
Converting HEAP To MyISAM   12.6 ms
Sending Data    25.5 s
Optimizing  82 µs
Statistics  54 µs
Preparing   38 µs
Executing   32 µs
Sorting Result  26 µs
Sending Data    186 µs
Removing Tmp Table  34 µs
Sending Data    34 µs
Waiting For Query Cache Lock    25 µs
Sending Data    76 µs
Init    96 µs
Optimizing  29 µs
Statistics  46 µs
Preparing   41 µs
Creating Tmp Table  118 µs
Executing   26 µs
Copying To Tmp Table    78.9 ms
Sorting Result  234 µs
Sending Data    252 µs
End     27 µs
Removing Tmp Table  27 µs
End     22 µs
Query End   22 µs
Closing Tables  22 µs
Removing Tmp Table  31 µs
Closing Tables  22 µs
Removing Tmp Table  6.8 ms
Closing Tables  62 µs
Removing Tmp Table  23 µs
Closing Tables  17 µs
Removing Tmp Table  19 µs
Closing Tables  46 µs
Freeing Items   64 µs
Logging Slow Query  21 µs
Logging Slow Query  76 µs
Cleaning Up     25 µs

Showing rows 0 - 13 ( 14 total, Query took 25.6179 sec)
4

4 回答 4

1

如果不使用临时表,您应该只需要对标准内的数据进行两次扫描,即可获得每个用户的评分以及所有用户对 gem 的评分。下面的例子被修改了。如果您在 gemid 上有一个正确的索引,那么它应该以毫秒为单位返回。但是,随着您将更多字段添加到结果中,您的选择分组将会增加。您可能希望将摘要和详细记录包装到第三个子查询中,以获取更详细的数据

SELECT *
FROM
(
      ....AGGRETATE QUERY HERE ONE RECORD PER GEM                   

)AS SUMMARY
LEFT OUTER JOIN 
(   
      ...DETAIL QUERY HERE FOR EACH USER AND EACH GEM       

)AS DETAIL ON DETAIL.gemid=SUMMARY.gemid
ORDER BY
    DETAIL.sort
于 2013-11-04T20:07:41.957 回答
1

鉴于您的回答,以及子查询rt在 .0010 秒内运行的事实,该查询应该可以正常工作:

SELECT 
    g.gemid as ggemid,     
    g.title as gtitle, 
    g.descr, 
    g.userid as guserid, 
    gemdetail.filename, 
    g.dateentered as gdateentered, 
    g.post, 
    g.sort as gsort, 
    g.grade as ggrade, 
    g.page as gpage, 
    g.page2 as gpage2, 
    g.tab as gtab, 
    concat(users.firstname,' ',users.lastname) AS gfullname, 
    g2.gemid as rgemid, 
    g2.title as rtitle, 
    g2.descr as rdescr, 
    g2.userid as ruserid, 
    gd.filename as rfilename, 
    g2.dateentered as rdateentered, 
    g2.post as rpost, 
    g2.sort as rsort, 
    concat(u2.firstname,' ',u2.lastname) as rfullname, 
    rt.sum_rating as gsum_rating, 
    rt.ave_experience as gave_experience, 
    rt.count_experience as gcount_experience, 
    rt.count_comments as gcount_comments 
FROM gems g 
    LEFT JOIN users         ON g.userid = users.userid  
    LEFT JOIN gemdetail     ON g.gemid = gemdetail.gemid  
    LEFT JOIN gems g2       ON g.gemid = g2.replygemid
    LEFT JOIN users u2      ON g2.userid = u2.userid 
    LEFT JOIN gemdetail gd  ON g2.gemid = gd.gemid  
    JOIN ( 
            SELECT 
                gemrating.gemid, 
                AVG(experience) as ave_experience, 
                SUM(rating) as sum_rating, 
                COUNT(experience) as count_experience, 
                COUNT(comments) as count_comments 
            FROM gems  
                LEFT JOIN gemrating ON gems.gemid = gemrating.gemid 
            WHERE 
                ISNULL(replygemid) 
            AND gems.tab = 0 
            AND gems.grade = '8' 
            AND gems.page='physics' 
            AND gems.page2='hydraulics'  
            GROUP BY gemrating.gemid
        ) rt ON g.gemid = rt.gemid
WHERE 
    ISNULL(g.replygemid) 
AND g.tab = 0 
AND g.grade = '8' 
AND g.page = 'physics' 
AND g.page2 = 'hydraulics'     
ORDER BY 
    gsort asc, 
    ggemid, 
    rsort, 
    filename

但我对这么少量的行如何需要 26 秒才能完成感到困惑。毕竟可能是硬件问题...

于 2013-11-05T03:03:24.160 回答
0

决赛- 作品

SELECT 
    g.gemid as ggemid,     
    g.title as gtitle, 
    g.descr, 
    g.userid as guserid, 
    gemdetail.filename as gfilename, 
    g.dateentered as gdateentered, 
    g.post, 
    g.sort as gsort, 
    g.grade as ggrade, 
    g.page as gpage, 
    g.page2 as gpage2, 
    g.tab as gtab, 
    concat(users.firstname,' ',users.lastname) AS gfullname, 
    g2.gemid as rgemid, 
    g2.title as rtitle, 
    g2.descr as rdescr, 
    g2.userid as ruserid, 
    gd.filename as rfilename, 
    g2.dateentered as rdateentered, 
    g2.post as rpost, 
    g2.sort as rsort, 
    concat(u2.firstname,' ',u2.lastname) as rfullname, 
    g.sum_rating as gsum_rating, 
    g.ave_experience as gave_experience, 
    g.count_experience as gcount_experience, 
    g.count_comments as gcount_comments 
    FROM 
    (Select gems.*, sum_rating, ave_experience, count_experience, count_comments FROM gems 
        LEFT JOIN ( 
            SELECT 
                gemrating.gemid, 
                AVG(experience) as ave_experience, 
                SUM(rating) as sum_rating, 
                COUNT(experience) as count_experience, 
                COUNT(comments) as count_comments 
            FROM gems  
                LEFT JOIN gemrating ON gems.gemid = gemrating.gemid 
            WHERE ISNULL(gems.replygemid) AND gems.tab =0 AND gems.grade = '6' AND gems.page='physics' AND gems.page2='optics' 
            GROUP BY gemrating.gemid
            ) rt ON gems.gemid = rt.gemid
        WHERE ISNULL(gems.replygemid) AND gems.tab =0 AND gems.grade = '6' AND gems.page='physics' AND gems.page2='optics' 
        ORDER BY title asc, sort, gemid 
        LIMIT 0, 100
    ") g 
    LEFT JOIN users         ON g.userid = users.userid  
    LEFT JOIN gemdetail     ON g.gemid = gemdetail.gemid  
    LEFT JOIN gems g2       ON g.gemid = g2.replygemid
    LEFT JOIN users u2      ON g2.userid = u2.userid 
    LEFT JOIN gemdetail gd  ON g2.gemid = gd.gemid
    ORDER BY gtitle asc, gsort, ggemid, rsort, gfilename, rfilename
于 2013-11-05T00:07:00.190 回答
0

以下是我一直在使用左连接或子查询进行查询的一些性能改进:

  1. 如果可能的话,我注意到在升级到 MySql 5.5 或 5.6 时有一个重大改进(在一个戏剧性的情况下,我的一个查询从 5.5 中的 20 秒变为 5.6 中的 <1 秒 - 5.6 在特定情况下有一些重大的性能提升,尤其是意见)
  2. 转换子查询时我注意到了一些改进
  3. 在 MyISAM 上使用 InnoDB 时,我注意到了一个重大改进

希望这可以帮助

于 2013-11-21T00:08:21.767 回答