我注意到,由于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
答案 0 :(得分:2)
一些观察结果:
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);
如果您没有索引,那么您最终会进行多次全表扫描,这很慢。
添加索引需要付出代价:它占用空间,这也意味着对表的写入速度较慢,因为索引必须更新才能包含它们。但是,如果这是一个作为网站操作的一部分运行的查询,那么你肯定需要索引。