如何提高mysql查询速度

发布于 2024-09-07 16:04:11 字数 613 浏览 1 评论 0原文

这是

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

这在执行时几乎杀死数据库,有人可以建议解决方案以使其更快吗?

我来这里是为了提供任何需要的额外信息。

谢谢。

here it is

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

This is almost killing DB when executing , can some suggest solution to make it speedy ?

I am here to provide any additional info needed.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

空袭的梦i 2024-09-14 16:04:11

您是否运行 EXPLAIN 命令来查看哪一部分查询运行缓慢?

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

Have you run an EXPLAIN command to see which part of the query is running slow?

Also, this line could be a problem: WHERE date LIKE '2010-07-02%' This could be causing the date column to be converted to a string (please tell me it's not a string!) which will prevent any index being used. Try WHERE DATE(date) = '2010-07-02' instead.

贪了杯 2024-09-14 16:04:11

这是我对您的查询的重写:

   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

Here's my re-write of your query:

   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
沉睡月亮 2024-09-14 16:04:11

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

如果子查询中有子查询,效果会更糟。效果成倍增加,因此如果外部返回 10 行,内部返回 10 行,那么最内部的将运行 100 次。

编辑:别介意最后一段——看起来你在子查询中有一个子查询,但再看一遍,你没有。无论哪种方式,都不要使用子查询。

Don't use subqueries. Each subquery runs once for every row. So if the outer query returns 10 rows, then the inner query will be run 10 times.

The effect is made even worse by the fact that you have a subquery in a subquery. The effect multiplies, so if the outer one returns 10 rows and the inner one returns 10 rows, then the inner most one will run 100 times.

Edit: never mind on that last paragraph--it looked like you had a subquery within a subquery, but looking at it again, you don't. Either way, don't use subqueries.

花落人断肠 2024-09-14 16:04:11

您可以做的最好的事情就是摆脱 LIKE 关键字,并简单地说:

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

这样,您将获得当天的所有内容(或您需要的任何日期范围)。最好的思考方式是 mySQL 必须遍历并评估每一行,即使它们已经是日期时间字段。如果定期搜索字段 v.Date,您可以在其上放置索引以加快搜索速度,然后它会使搜索速度更快,因为它会知道数据已经在哪里。

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

The best thing you could do is get rid of the LIKE keyword, and simply say:

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

That way, you'll get everything for the day (or whatever date range you need to). The best way to think about it is that mySQL will have to go through and evaluate each row, even though they're already a datetime field. If the field v.Date is regularly searched, you could put an index on it to speed things up, and then it will make things quicker because it'll have an idea where the data is already.

You can also use COUNT(ID) instead of counting everything. Counting one field instead of 10 or 20 or 50 can save a few milliseconds.

花落人断肠 2024-09-14 16:04:11
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 
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 
╰つ倒转 2024-09-14 16:04:11

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

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 ;

You can try this (without data it is hard to test)

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

Is this data structure correct?

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 ;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文