我有一个收集网页性能数据的表格。有多台机器,以10分钟的间隔测试多个站点,所以目前我有大约70万行(920 MB),每天有+/- 50,000个新行。
表来源:
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
CREATE TABLE `http_perf_raw_log` (
`run_dt` int(11) DEFAULT NULL,
`dataset` varchar(64) DEFAULT NULL,
`runner` varchar(64) DEFAULT NULL,
`site` varchar(128) DEFAULT NULL,
`machine` varchar(32) DEFAULT NULL,
`called_url` varchar(1024) DEFAULT NULL,
`method` varchar(8) DEFAULT NULL,
`url` varchar(1024) DEFAULT NULL,
`content_type` varchar(64) DEFAULT NULL,
`http_code` int(11) DEFAULT NULL,
`header_size` int(11) DEFAULT NULL,
`request_size` int(11) DEFAULT NULL,
`filetime` int(11) DEFAULT NULL,
`ssl_verify_result` int(11) DEFAULT NULL,
`redirect_count` int(11) DEFAULT NULL,
`total_time` decimal(6,4) DEFAULT NULL,
`namelookup_time` decimal(6,4) DEFAULT NULL,
`connect_time` decimal(6,4) DEFAULT NULL,
`pretransfer_time` decimal(6,4) DEFAULT NULL,
`starttransfer_time` decimal(6,4) DEFAULT NULL,
`redirect_time` decimal(6,4) DEFAULT NULL,
`size_upload` int(11) DEFAULT NULL,
`size_download` int(11) DEFAULT NULL,
`speed_download` int(11) DEFAULT NULL,
`speed_upload` int(11) DEFAULT NULL,
`download_content_length` int(11) DEFAULT NULL,
`upload_content_length` int(11) DEFAULT NULL,
`certinfo` varchar(1024) DEFAULT NULL,
`request_header` varchar(1024) DEFAULT NULL,
`return_content` varchar(4096) DEFAULT NULL,
`return_headers` varchar(2048) DEFAULT NULL,
KEY `run_dt_idx` (`run_dt`),
KEY `dataset_idx` (`dataset`),
KEY `runner_idx` (`runner`),
KEY `site_idx` (`site`),
KEY `machine_idx` (`machine`),
KEY `total_time_idx` (`total_time`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
为了汇总统计数据(分辨率为1小时),我创建了一个视图:
CREATE OR REPLACE VIEW http_perf_stats (dataset, runner, site, machine, day, hour, calls, total_time, namelookup_time, connect_time, pretransfer_time, starttransfer_time, size_download) AS
SELECT dataset, runner, site, machine,
DATE_FORMAT(run_dt, '%Y-%m-%d') AS day,
DATE_FORMAT(run_dt, '%k') AS hour,
COUNT(*) AS calls,
SUM(total_time),
SUM(namelookup_time),
SUM(connect_time),
SUM(pretransfer_time),
SUM(starttransfer_time),
SUM(size_download)
FROM http_perf_raw_log GROUP BY runner, site, machine, day, hour ORDER BY `day` DESC
但是VIEW(和基础SELECT)的表现非常糟糕 - 大约需要4秒钟。
所以,我的问题:
1。在VIEW中使用GROUP BY是个好主意吗?如果没有,还有什么更好的替代方案?
2。有没有(我想是的,我不是SQL专家:/)一种优化这种SELECT的方法(改变http_perf_raw_log的查询或结构)?
答案 0 :(得分:2)
在这种情况下,最好只定期创建统计数据(例如每小时一次)。
我会这样做。运行以下代码一次以创建表结构。
CREATE TABLE http_perf_stats AS
SELECT dataset, runner, site, machine,
DATE_FORMAT(run_dt, '%Y-%m-%d') AS day,
DATE_FORMAT(run_dt, '%k') AS hour,
COUNT(*) AS calls,
SUM(total_time),
SUM(namelookup_time),
SUM(connect_time),
SUM(pretransfer_time),
SUM(starttransfer_time),
SUM(size_download)
FROM http_perf_raw_log
GROUP BY runner, site, machine, day, hour
ORDER BY `day` DESC
进行一些修改,例如更改字段类型,默认值,添加主键,以及添加一些索引,以便您可以快速访问和查询此表。
从那时起,像这样更新表格:
START TRANSACTION;
DELETE FROM http_perf_stats;
INSERT INTO TABLE
SELECT dataset, runner, site, machine,
DATE_FORMAT(run_dt, '%Y-%m-%d') AS day,
DATE_FORMAT(run_dt, '%k') AS hour,
COUNT(*) AS calls,
SUM(total_time),
SUM(namelookup_time),
SUM(connect_time),
SUM(pretransfer_time),
SUM(starttransfer_time),
SUM(size_download)
FROM http_perf_raw_log
GROUP BY runner, site, machine, day, hour
ORDER BY `day` DESC;
COMMIT;
有几种方法可以做到这一点:
创建一个MySQL事件(参见http://dev.mysql.com/doc/refman/5.1/en/create-event.html)(我就是这样做的)
创建一个cron作业(unix风格的系统)或窗口调度程序任务
进行“懒惰”更新。当有人请求此列表时,如果上次运行的时间长于x分钟/小时,请运行上面的代码。这样它更像缓存。第一次请求慢,之后很快。但除非有人对此感兴趣,否则你不会放慢服务器速度。
答案 1 :(得分:1)
从VIEW中移除GROUP BY
,并在调用SELECT
的{{1}}中使用它。
答案 2 :(得分:0)
视图只是另一个SELECT查询,但是抽象出来以便更容易查询结果集。如果底层的SELECT很慢,那么视图也是如此。在4秒内读取和汇总1 GB数据对我来说听起来并不慢。