代码之家  ›  专栏  ›  技术社区  ›  Arshdeep

如何提高这个MySQL查询的速度

  •  0
  • Arshdeep  · 技术社区  · 14 年前

    这里是

    SELECT tbl_rls . * , (
    
    SELECT count( * )
    FROM `comments`
    WHERE `post_id` = `tbl_rls`.`id`
    ) AS `t_comments`
    FROM `tbl_rls`
    WHERE 1 =1
    AND `status` <> 'denied'
    AND (
    `id`
    IN (
    
    SELECT `rls_id`
    FROM `tbl_visitors_logs`
    WHERE `date` LIKE '2010-07-02%'
    AND `page_type` = 'post'
    GROUP BY `rls_id`
    ORDER BY count( * ) DESC
    )
    )
    AND (
    `cat` = '6'
    OR `cat`
    IN (
    
    SELECT `id`
    FROM `tbl_cats`
    WHERE `parent_id` = '6'
    )
    )
    ORDER BY `tbl_rls`.`date` DESC
    LIMIT 0 , 20
    

    在执行时,这几乎要杀死数据库,有人能建议解决方案使其快速运行吗?

    我在这里提供所需的任何附加信息。

    谢谢。

    6 回复  |  直到 12 年前
        1
  •  1
  •   jcubic    12 年前

    这是我对你的问题的回复:

       SELECT t. *, 
              x.t_comments
         FROM tbl_rls t
    LEFT JOIN (SELECT c.post_id,
                      COUNT(*) AS t_comments
                 FROM COMMENTS c
             GROUP BY t.post_id) x ON x.post_id = t.id
         JOIN tbl_visitors_logs tvl ON tvl.rls_id = t.id
                                   AND tvl.date LIKE '2010-07-02%'
                                   AND tvl.page_type = 'post'
        WHERE t.status != 'denied'
          AND (t.cat = '6' OR t.cat IN (SELECT `id`
                                          FROM `tbl_cats`
                                         WHERE `parent_id` = '6'))
    ORDER BY t.`date` DESC
       LIMIT 0, 20
    
        2
  •  2
  •   Ken Keenan    14 年前

    你跑了吗? EXPLAIN 命令查看查询的哪个部分运行缓慢?

    此外,此行可能是一个问题: WHERE date LIKE '2010-07-02%' 这可能导致日期列转换为字符串(请告诉我它不是字符串!)这将阻止使用任何索引。尝试 WHERE DATE(date) = '2010-07-02' 相反。

        3
  •  1
  •   riwalk    14 年前

    不要使用子查询。每行运行一次子查询。因此,如果外部查询返回10行,则内部查询将运行10次。

    由于在子查询中有一个子查询,效果会更糟。这样,如果外部的返回10行,内部的返回10行,则内部最大的将运行100次。

    编辑:别介意最后一段--看起来你在子查询中有一个子查询,但是再看一次,你就没有了。不管怎样,都不要使用子查询。

        4
  •  1
  •   user174624    14 年前

    你能做的最好的事情就是去掉like关键字,然后简单地说:

    WHERE v.Date > '2010-07-02' AND v.Date < '2010-07-03'
    

    这样,您就可以获得当天的所有信息(或您需要的任何日期范围)。考虑到这一点,最好的方法是MySQL必须遍历并评估每一行,即使它们已经是一个日期时间字段。如果定期搜索字段v.date,您可以在其上放置索引以加快速度,然后它将使速度更快,因为它将知道数据的位置。

    您还可以使用count(id)而不是计算所有内容。计算一个字段而不是10、20或50可以节省几毫秒。

        5
  •  1
  •   jcubic    12 年前
    SELECT tbl_rls.*, 
           COUNT(distinct comments.id) AS t_comments 
      FROM tbl_rls 
           JOIN tbl_visitors_logs tvl ON tvl.rls_id = tbl_rls.id
            AND tvl.page_type =  'post'
            AND DATE(tvl.date) = '2010-07-02'
           LEFT JOIN comments ON comments.post_id = tbl_rls.id
           LEFT JOIN tbl_cats ON tbl_cats.id =  cat AND tbl_cats.parent_id = '6'
     WHERE status <> 'denied' 
       AND (cat = 6 OR tbl_cats.id is not null)
     GROUP BY tbl_rls.id                           
     ORDER BY tbl_rls.date DESC 
     LIMIT 0, 20 
    
        6
  •  1
  •   jcubic    12 年前

    你可以试试这个(没有数据很难测试)

    SELECT r.*, COUNT(c.id) 
    FROM tbl_rls r, comments c, tbl_visitors_logs v, tbl_cats t 
    WHERE c.post_id = r.id 
        AND v.rls_id = r.id 
        AND t.parent_id = r.cat 
        AND r.status <> 'denied' 
        AND v.`date` LIKE '2010-07-02%' 
        AND page_type = 'post' 
        AND cat = 6 OR t.parent_id = 6 
    GROUP BY c.post_id 
    ORDER BY r.`date` DESC 
    LIMIT 0, 20
    

    此数据结构是否正确?

    CREATE TABLE IF NOT EXISTS `tbl_cats` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `parent_id` int(11) NOT NULL,
      `name` varchar(10) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
    
    CREATE TABLE IF NOT EXISTS `tbl_rls` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `status` varchar(10) NOT NULL,
      `cat` int(11) NOT NULL,
      `date` date NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
    
    CREATE TABLE IF NOT EXISTS `tbl_visitors_logs` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `rls_id` int(11) NOT NULL,
      `date` date NOT NULL,
      `page_type` varchar(10) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
    
    CREATE TABLE IF NOT EXISTS `comments` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `post_id` int(11) NOT NULL,
      `commetn` varchar(50) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;