Mysql服务器因为一个查询而烧毁,是否可能?如何加快速度?

时间:2014-01-23 07:13:01

标签: mysql mysqli

我注意到,由于Mysqld在高峰时段出现问题,因此编写SQL查询时遇到问题。它导致我的网站加载比平时慢3-5倍。所以我试过siege -d5 -c150 http://mydomain.com/并查看了top,我的mysqld占用了超过700%的CPU!我也注意到mysql状态:Copying to tmp table并且查询添加到某个队列或类似的东西。

  PID USER      PR  NI  VIRT  RES  SHR S  %CPU %MEM    TIME+  COMMAND
25877 mysql     20   0 1076m 227m 8268 S 749.0  2.8 224:02.21 mysqld

这是我的查询

SELECT COUNT(downloaded.id) AS downloaded_count
    , downloaded.file_name
    ,uploaded.* 
FROM `downloaded` JOIN uploaded 
ON downloaded.file_name = uploaded.file_name 
WHERE downloaded.completed = '1' 
AND uploaded.active = '1' 
AND uploaded.nsfw = '0' 
AND downloaded.datetime > DATE_SUB(NOW(), INTERVAL 7 DAY) 
GROUP BY downloaded.file_name 
ORDER BY downloaded_count DESC LIMIT 30;

显示0到29行(总共30行,查询花了0.1639秒)//这么多吗?不应该是0.01s而不是吗?

更新:(已删除ORDER BY)

显示0到29行(总计30行,查询耗时0.0064秒) 为什么ORDER BY会让它慢20倍?

EXPLAIN

+----+-------------+------------+------+---------------+-----------+---------+--------------------------+------+----------------------------------------------+
| id | select_type | table      | type | possible_keys | key       | key_len | ref                      | rows | Extra                                        |
+----+-------------+------------+------+---------------+-----------+---------+--------------------------+------+----------------------------------------------+
|  1 | SIMPLE      | uploaded   | ALL  | file_name_up  | NULL      | NULL    | NULL                     | 3139 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | downloaded | ref  | file_name     | file_name | 767     | piqik.uploaded.file_name |    8 | Using where                                  |
+----+-------------+------------+------+---------------+-----------+---------+--------------------------+------+----------------------------------------------+

表:已上传(总计720.5 KiB)

CREATE TABLE IF NOT EXISTS `uploaded` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sid` int(1) NOT NULL,
  `file_name` varchar(255) NOT NULL,
  `file_size` varchar(255) NOT NULL,
  `file_ext` varchar(255) NOT NULL,
  `file_name_keyword` varchar(255) NOT NULL,
  `access_key` varchar(40) NOT NULL,
  `upload_datetime` datetime NOT NULL,
  `last_download` datetime NOT NULL,
  `file_password` varchar(255) NOT NULL DEFAULT '',
  `nsfw` int(1) NOT NULL,
  `votes` int(11) NOT NULL,
  `downloads` int(11) NOT NULL,
  `video_thumbnail` int(1) NOT NULL DEFAULT '0',
  `video_duration` varchar(255) NOT NULL DEFAULT '',
  `video_resolution` varchar(11) NOT NULL,
  `video_additional` varchar(255) NOT NULL DEFAULT '',
  `active` int(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  FULLTEXT KEY `file_name_keyword` (`file_name_keyword`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3328 ;

表:已下载(总计5,152.0 KiB)

CREATE TABLE IF NOT EXISTS `downloaded` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `file_name` varchar(255) NOT NULL,
  `completed` int(1) NOT NULL,
  `client_ip_addr` varchar(40) NOT NULL,
  `client_access_key` varchar(40) NOT NULL,
  `datetime` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=31475 ;

(不知道我为什么选择InnoDB)

请注意,我(仍然)没有使用索引(我读的非常重要!)因为缺乏知识而且我不确定如何正确添加它们。

所以问题是,如何改进此查询以防止网络服务器缓慢加载网站?我只有“少数”记录,无法相信我遇到了如此重大的问题,这里的人们处理数百万条记录并且他们的项目有效。网站托管公司如何防止这个问题? (我只托管我的网页,有超过150个并发客户端)

其他信息:

Mysql:5.5.33

Nginx 1.2.1,php5-fpm

Debian 7.1 Wheezy

2x L5420 @ 2.50GHz

8GB RAM

1 个答案:

答案 0 :(得分:2)

一些观察结果:

  • 您可能没有主动选择InnoDB作为存储引擎:它将是您的MySQL版本的默认引擎。但是,它可能是您的上下文的正确选择,因为它提供了行级锁定而不是您可能想要的表级锁定(以及其他内容)。
  • 不要在比较中引用整数(例如uploaded.active = '1')。你最终会得到较慢的字符串比较,而不是整数比较。
  • 与派生值的比较downloaded.datetime > DATE_SUB(NOW(), INTERVAL 7 DAY)将比与普通列值的比较慢。

关于最后一点,您可以将其替换为在查询之前声明的用户定义变量:

SET @one_week_ago := DATE_SUB(NOW(), INTERVAL 7 DAY);

然后在查询中与该预先计算的值进行比较:

...
downloaded.datetime > @one_week_ago
...

更重要的是,您肯定希望在您加入的任何密钥上都有索引。

在这种情况下,您可以通过以下方式添加它们:

CREATE INDEX idx_file_name ON uploaded(file_name);
CREATE INDEX idx_file_name ON downloaded(file_name);

如果您没有索引,那么您最终会进行多次全表扫描,这很慢。

添加索引需要付出代价:它占用空间,这也意味着对表的写入速度较慢,因为索引必须更新才能包含它们。但是,如果这是一个作为网站操作的一部分运行的查询,那么你肯定需要索引。