慢SQL查询 - 找不到

时间:2012-03-05 19:39:59

标签: 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

无法在我的页面上运行。即使在每次更改我的代码并且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;

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

另外,上述方法是否有效?我有另一个关于这个问题的线程(一般来说是数据库),没有人回答过我的问题。

支持给了我很少的帮助,并不断向我推荐明显的东西。我认为最重要的是自从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

解释上述内容:

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

解释最初的“问题”查询:

  

1 PRIMARY uploadsNew ref type,type_2 type_2 8 const,const 1896 Using   哪里;使用临时;使用filesort   1 PRIMARY ALL NULL 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使用   哪里;使用临时;使用filesort   2 DERIVED views ref type type 4 688使用where;使用临时;   使用filesort

观看表格

  

CREATE TABLE viewsid int(10)NOT NULL DEFAULT'0',type   int(1)NOT NULL DEFAULT'0',subtype int(1)NOT NULL DEFAULT'0',   date datetime NOT NULL,ip int(20)NOT NULL DEFAULT'0',user   varchar(20)NOT NULL,KEY ididtype),KEY id_2   (idtypesubtype),键id_3idtypedate),键{{1 }}   (typetype))ENGINE = MyISAM DEFAULT CHARSET = latin1

viewsCondensed table:

  

CREATE TABLE ipviewsCondensed int(10)NOT NULL DEFAULT'0',   id int(1)NOT NULL DEFAULT'0',type int(1)NOT NULL DEFAULT   '0',subtype date NOT NULL,date int(10)NOT NULL DEFAULT'0',KEY   viewsidid),键typeid_2idtype),键{{1} }   (subtypeid_3id),键typedatetype),键type   (viewstype_2type),键subtypeviewstype_3type),KEY   dateviews))ENGINE = MyISAM DEFAULT CHARSET = latin1

uploadsNew table:

  

CREATE TABLE type_4type int(10)NOT NULL AUTO_INCREMENT,   uploadsNew varchar(30)NOT NULL,id int(20)NOT NULL,member   varchar(30)NOT NULL,ip int(1)NOT NULL,gallery varchar(30)NOT   NULL,type int(1)NOT NULL,genre int(6)NOT NULL,anonymous   datetime NOT NULL,school datetime NOT NULL,added varchar(255)   NOT NULL,approved varchar(2500)NOT NULL,title varchar(300)NOT   NULL,content varchar(40)NOT NULL,url varchar(200)NOT NULL,   address int(1)NOT NULL,tags int(1)NOT NULL,rating   varchar(600)NOT NULL,PRIMARY KEY(status),KEY source   (ididid),键member   (statustypetypegenreapproved),键rating   (statustype_2))ENGINE = MyISAM AUTO_INCREMENT = 6004 DEFAULT   CHARSET = latin1的

评级新表:

  

CREATE TABLE typestatus int(10)NOT NULL,ratingNew int(1)   NOT NULL DEFAULT'0',upload varchar(20)NOT NULL,type int(16)   NOT NULL,username int(1)NOT NULL,ip datetime NOT NULL,KEY   ratingdateupload))ENGINE = MyISAM DEFAULT CHARSET = latin1


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

新查询

upload

解释

type

2 个答案:

答案 0 :(得分:6)

  1. PRIMARY KEY的{​​{1}}是什么?是uploadsNew吗?如果是,请删除id。它应该给出相同的结果。

  2. 你对表有什么指数?如果还没有,请添加:

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

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

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

  6. 添加我在上面评论2中添加的索引。唯一可能不是最好的是表PRIMARY KEY中的(type, upload, rating)。它可能必须是:ratingNew,但如果该表的行数不多,那么现在就不会有问题了。

  7. 您的代码会生成查询的多个变体。因此,您还需要添加此索引:表(type, upload, username, rating)中的(type, status, approved)

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

    uploadsNew

答案 1 :(得分:0)

你永远不应该使用子选择,而是重新格式化它以使用它就像标准的左连接一样。

我很难解析你的代码,所以如果你可以将SQL STRING构建的结果粘贴给我们,我们就能够尽可能地重新格式化它。