慢SQL查询 - 找不到

Jam*_*D31 0 php mysql sql performance

好的,所以我的托管公司暂停我的帐户第四次该死的时间.这让我很烦,因为他们说的代码导致了这个问题:

# Mon Mar  5 11:00:00 2012
# Query_time: 4.028706  Lock_time: 0.000272 Rows_sent: 15  Rows_examined: 12188513 use futureg2_imbc; 

SELECT uploadsNew.id   ,
    uploadsNew.title   , uploadsNew.genre   , uploadsNew.content   ,
    uploadsNew.url   , uploadsNew.approved, (IF(v.views IS NOT NULL,
    v.views, 0) + IF(vc.old_views IS NOT NULL, vc.old_views, 0)) AS views,
    r.likes   , r.dislikes FROM uploadsNew   
  LEFT JOIN    
    (SELECT id   ,
      COUNT(*) AS views   
     FROM views   
    WHERE type = '0' AND subtype = '1'  
    GROUP BY id   
    ) AS v   
  ON v.id = uploadsNew.id   
  LEFT JOIN   
    (SELECT
      id   , SUM(views) AS old_views   
    FROM viewsCondensed   
    WHERE type = '0' AND subtype = '1'   
    GROUP BY id   
    ) AS vc   
  ON vc.id = uploadsNew.id   
  LEFT JOIN   
    (SELECT upload   , SUM(IF(rating = '1', 1, 0)) AS likes   , 
      SUM(IF(rating = '-1', 1, 0)) AS dislikes   ,
      IF(username = '', rating, 0) AS user_rated   
    FROM ratingNew   
    WHERE ratingNew.type = '0'   
    GROUP BY upload ) AS r   
  ON r.upload = uploadsNew.id   
  WHERE uploadsNew.type = '1'   AND uploadsNew.status ='0'   AND 
    uploadsNew.school = 'illinois-state-university'   
GROUP BY
  uploadsNew.id ORDER BY uploadsNew.approved DESC LIMIT 15
Run Code Online (Sandbox Code Playgroud)

不能在我的页面上运行.即使在每次更改我的代码并且100次查看它之后,这仍然是一个问题,并且它是完全相同的代码,每次运行多次,每次他们暂停我的帐户.

这是PHP代码:

$sql = "SELECT uploadsNew.id
    , uploadsNew.title
    , uploadsNew.genre
    , uploadsNew.content
    , uploadsNew.url
    , uploadsNew.approved";
if($type < 3) $sql .= ", (IF(v.views IS NOT NULL, v.views, 0) + IF(vc.old_views IS NOT NULL, vc.old_views, 0)) AS views";
else $sql .= ", uploadsNew.member
    , uploadsNew.anonymous
    , r.ratedSong";
$sql .= ", r.likes
    , r.dislikes";
if($sort == "rated") $sql .= ", (r.likes - r.dislikes) AS rating";
if(isset($school)) $sql .= ", s.school_id";
$sql .= " FROM uploadsNew";
if(isset($school)) $sql .= " LEFT JOIN (SELECT url, id AS school_id FROM schools) AS s ON s.url = '". $school ."'";
$sql .= " LEFT JOIN 
            (SELECT id
                , COUNT(*) AS views
            FROM views
            WHERE type = '0' AND subtype = '". $type ."'
            GROUP BY id
            ) AS v
            ON v.id = uploadsNew.id
        LEFT JOIN
            (SELECT id
                , SUM(views) AS old_views
            FROM viewsCondensed
            WHERE type = '0' AND subtype = '". $type ."'
            GROUP BY id
            ) AS vc
            ON vc.id = uploadsNew.id
        LEFT JOIN
            (SELECT upload
                , SUM(IF(rating = '1', 1, 0)) AS likes
                , SUM(IF(rating = '-1', 1, 0)) AS dislikes
                , IF(username = '". $user['username'] ."', rating, 0) AS user_rated
            FROM ratingNew
            WHERE ratingNew.type = '0'
            GROUP BY upload
            ) AS r
            ON r.upload = uploadsNew.id
        WHERE uploadsNew.type = '". $type ."' AND uploadsNew.status = '0'";
if($genre) $sql .= " AND uploadsNew.genre = '". strtolower($genre) ."'";
if(isset($school)) $sql .= " AND uploadsNew.school = s.school_id";
else $sql .= $filter;
$sql .= " GROUP BY uploadsNew.id ORDER BY ". $s ." LIMIT ". ($page - 1) * $limit .", ". $limit;
Run Code Online (Sandbox Code Playgroud)

如果有人甚至可以弄清楚上面引用的代码甚至可以从单个查询中运行 - 请随意.此外,如果你能弄清楚它是如何每秒运行多次(就好像它是循环的)我会更爱你.

另外,上述方法是否有效?我有另一个关于此问题的线索(以及一般的数据库),没有人回答过我的问题.

支持给了我很少的帮助,并不断向我推荐明显的东西.我觉得最重要的是自从viewsCondensed表大约是〜80k的东西.

基本上,viewsCondensed表用于将所有内容(在视图表中)的每日视图压缩为完全每日总和(viewsCondensed).

我应该把它改成每周的东西,还是每月的东西?我曾经把所有这些只是在uploadsNew表中的一部分,虽然我觉得这样效率有点低,并且不允许每天保存实际数据.

任何和所有帮助都会得到很多赞赏!


对不起,这里有关于SELECT以及各种表的EXPLAIN的更多数据:

这是一个NORMAL查询,它在前一个"运行"的页面上运行:

SELECT uploadsNew.id
  , uploadsNew.title
  , uploadsNew.genre
  , uploadsNew.content
  , uploadsNew.url
  , uploadsNew.approved, (IF(v.views IS NOT NULL, v.views, 0) + IF(vc.old_views IS NOT NULL, vc.old_views, 0)) AS views, r.likes
  , r.dislikes FROM uploadsNew
  LEFT JOIN 
  (SELECT id
  , COUNT(*) AS views
  FROM views
  WHERE type = '0' AND subtype = '1'
  GROUP BY id
  ) AS v
  ON v.id = uploadsNew.id
  LEFT JOIN
  (SELECT id
  , SUM(views) AS old_views
  FROM viewsCondensed
  WHERE type = '0' AND subtype = '1'
  GROUP BY id
  ) AS vc
  ON vc.id = uploadsNew.id
  LEFT JOIN
  (SELECT upload
  , SUM(IF(rating = '1', 1, 0)) AS likes
  , SUM(IF(rating = '-1', 1, 0)) AS dislikes
  , IF(username = '', rating, 0) AS user_rated
  FROM ratingNew
  WHERE ratingNew.type = '0'
  GROUP BY upload
  ) AS r
  ON r.upload = uploadsNew.id
  WHERE uploadsNew.type = '1'
  AND uploadsNew.status = '0'
  GROUP BY uploadsNew.id ORDER BY uploadsNew.approved DESC LIMIT 15
Run Code Online (Sandbox Code Playgroud)

解释上面的内容:

1 PRIMARY uploadsNew     ref type,type_2               type_2 8 const,const 1965 Using temporary; Using filesort
1 PRIMARY <derived2>     ALL NULL                      NULL   NULL NULL     1335
1 PRIMARY <derived3>     ALL NULL                      NULL   NULL NULL     5429
1 PRIMARY <derived4>     ALL NULL                      NULL   NULL NULL      372
4 DERIVED ratingNew      ALL NULL                      NULL   NULL NULL     2111 Using where; Using temporary; Using filesort
3 DERIVED viewsCondensed ref type,type_2,type_3,type_4 type_2 8            67475 Using where; Using temporary; Using filesort
2 DERIVED views        index type                      id_2   12   NULL     4351 Using where; Using index
Run Code Online (Sandbox Code Playgroud)

解释最初的"问题"查询:

1 PRIMARY uploadsNew ref type,type_2 type_2 8 const,const 1896使用where; 使用临时; 使用filesort 1 PRIMARY ALL NULL NULL NULL 479 1 PRIMARY ALL NULL NULL NULL NULL 6015
1 PRIMARY ALL NULL NULL NULL NULL 384 4 DERIVED ratingNew ALL NULL NULL NULL NULL 2171使用where; 使用临时; 使用filesort 3 DERIVED viewsCondensed ref type,type_2,type_3,type_4 type_3 4 53779使用where; 使用临时; 使用filesort 2 DERIVED视图ref类型类型4 688使用where; 使用临时; 使用filesort

观点表:

CREATE TABLE views(idint(10)NOT NULL DEFAULT'0',type int(1)NOT NULL DEFAULT'0',subtypeint(1)NOT NULL DEFAULT'0', datedatetime NOT NULL,ipint(20)NOT NULL DEFAULT'0' ,user VARCHAR(20)NOT NULL,KEY id(id,type),KEY id_2 (id,type,subtype),KEY id_3(id,type,date),KEY type (type,ip))ENGINE = MyISAM的默认字符集= LATIN1

viewsCondensed表:

CREATE TABLE viewsCondensed(idint(10)NOT NULL DEFAULT'0', typeint(1)NOT NULL DEFAULT'0',subtypeint(1)NOT NULL DEFAULT'0',datedate NOT NULL,viewsint(10)NOT NULL DEFAULT'0' ,KEY id(id,type),KEY id_2(id,type,subtype),KEY id_3 (id,type,date),KEY type(type,views),KEY type_2 (type,subtype,views),KEY type_3(type,date,views),KEY type_4(type))ENGINE = MyISAM的默认字符集= LATIN1

uploadsNew表:

CREATE TABLE uploadsNew(idint(10)NOT NULL AUTO_INCREMENT, membervarchar(30)NOT NULL,ipint(20)NOT NULL,gallery varchar(30)NOT NULL,typeint(1)NOT NULL,genrevarchar(30)NOT NULL,anonymousint(1) NOT NULL,schoolINT(6)NOT NULL,added 日期时间NOT NULL,approved日期时间NOT NULL,titleVARCHAR(255)NOT NULL,contentVARCHAR(2500)NOT NULL,urlVARCHAR(300)NOT NULL,addressVARCHAR(40)NOT NULL,tagsVARCHAR(200) NOT NULL, ratingINT(1)NOT NULL,statusINT(1)NOT NULL,source VARCHAR(600)NOT NULL,PRIMARY KEY( id),KEY id (id,member,status),KEY type (type,genre,approved,rating,status),KEY type_2 (type,status))ENGINE = MyISAM AUTO_INCREMENT = 6004 DEFAULT CHARSET = latin1

评级新表:

CREATE TABLE ratingNew(uploadint(10)NOT NULL,typeint(1)NOT NULL DEFAULT'0',usernamevarchar(20)NOT NULL,ipint(16)NOT NULL,ratingint(1)NOT NULL,datedatetime NOT NULL,KEY upload(upload,type) )ENGINE = MyISAM DEFAULT CHARSET = latin1


更多编辑(尝试新的查询和解释):

新查询

SELECT 
    uploadsNew.id,     uploadsNew.title, 
    uploadsNew.genre,  uploadsNew.content,
    uploadsNew.url,    uploadsNew.approved, 
    COALESCE(v.views, 0) + COALESCE(vc.old_views, 0) AS views,
    r.likes,           r.dislikes 
FROM  ( SELECT *
        FROM uploadsNew
        WHERE type = 1  
          AND status = 0  
        ORDER BY approved DESC 
        LIMIT 15
      ) AS uploadsNew  
  LEFT JOIN    
      ( SELECT  id,  COUNT(*) AS views   
        FROM views   
        WHERE type = 0 AND subtype = 1  
        GROUP BY id   
      ) AS v   ON v.id = uploadsNew.id   
  LEFT JOIN   
      ( SELECT  id,  SUM(views) AS old_views   
        FROM viewsCondensed   
        WHERE type = 0 AND subtype = 1   
        GROUP BY id   
      ) AS vc  ON vc.id = uploadsNew.id   
  LEFT JOIN   
      ( SELECT  upload, 
                SUM(rating = 1 ) AS likes, 
                SUM(rating = -1) AS dislikes,
                IF(username = '', rating, 0) AS user_rated   
        FROM ratingNew   
        WHERE type = 0   
        GROUP BY upload 
      ) AS r   ON r.upload = uploadsNew.id   
ORDER BY uploadsNew.approved DESC 
Run Code Online (Sandbox Code Playgroud)

解释

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY <derived2>  ALL NULL    NULL    NULL    NULL    15  Using temporary; Using filesort
1   PRIMARY <derived3>  ALL NULL    NULL    NULL    NULL    479 
1   PRIMARY <derived4>  ALL NULL    NULL    NULL    NULL    6015    
1   PRIMARY <derived5>  ALL NULL    NULL    NULL    NULL    384 
5   DERIVED ratingNew   index   NULL    upload_3    34  NULL    2171    Using where; Using index
4   DERIVED viewsCondensed  ref type,type_2,type_3,type_4   type_3  4       53779   Using where; Using temporary; Using filesort
3   DERIVED views   ref type    type    4       688 Using where; Using temporary; Using filesort
2   DERIVED uploadsNew  range   type,type_2,type_3,type_4   type_4  4   NULL    5970    Using where
Run Code Online (Sandbox Code Playgroud)

ype*_*eᵀᴹ 6

  1. 是什么PRIMARY KEYuploadsNew?是id吗?如果是,请删除GROUP BY uploadsNew.id.它应该给出相同的结果.

  2. 你在桌子上有什么指数?如果还没有,请添加:

    • (type, subtype, id)表中的索引views
    • (type, subtype, id, views)表中的索引viewsCondensed.
    • (type, upload, rating)表中的索引 ratingNew.
    • (type, status, school, approved)表中的索引uploadsNew.
  3. 然后,(不要运行查询),但使用EXPLAIN语句获取查询计划并在此处发布.如果添加表的定义(因此我们知道您拥有的数据类型和索引)也会很好.

  4. 你的几张桌子没有PRIMARY KEY.这不好,但这并不是这两个查询缓慢的原因,所以暂时忘记它(但你应该稍后处理).

  5. 你有几个冗余索引,但这不是上述查询性能下降的原因,所以我们也跳过这个(但是你也应该稍后处理).

  6. 添加我在上面的评论2中添加的索引.唯一可能不是最好的是(type, upload, rating)表格ratingNew.它可能必须是:(type, upload, username, rating)相反,但如果该表没有很多行,它现在不会成为问题.

  7. 您的代码会生成查询的多个变体.所以,你们许多人也必须添加这个索引:(type, status, approved)在表中uploadsNew.

然后,首先尝试解析此变体,然后运行它:

SELECT 
    uploadsNew.id,     uploadsNew.title, 
    uploadsNew.genre,  uploadsNew.content,
    uploadsNew.url,    uploadsNew.approved, 
    COALESCE(v.views, 0) + COALESCE(vc.old_views, 0) AS views,
    r.likes,           r.dislikes 
FROM  ( SELECT *
        FROM uploadsNew
        WHERE type = 1  
          AND status = 0  
          AND school = 'illinois-state-university'   
        ORDER BY approved DESC 
        LIMIT 15
      ) AS uploadsNew  
  LEFT JOIN    
      ( SELECT  id,  COUNT(*) AS views   
        FROM views   
        WHERE type = 0 AND subtype = 1  
        GROUP BY id   
      ) AS v   ON v.id = uploadsNew.id   
  LEFT JOIN   
      ( SELECT  id,  SUM(views) AS old_views   
        FROM viewsCondensed   
        WHERE type = 0 AND subtype = 1   
        GROUP BY id   
      ) AS vc  ON vc.id = uploadsNew.id   
  LEFT JOIN   
      ( SELECT  upload, 
                SUM(rating = 1 ) AS likes, 
                SUM(rating = -1) AS dislikes,
                IF(username = '', rating, 0) AS user_rated   
        FROM ratingNew   
        WHERE type = 0   
        GROUP BY upload 
      ) AS r   ON r.upload = uploadsNew.id   
ORDER BY uploadsNew.approved DESC 
Run Code Online (Sandbox Code Playgroud)