2011-04-24 106 views
4

我有一个表为网页性能收集数据。有多台机器,每间隔10分钟测试多个站点,所以目前我每天有大约700 000行(920 MB)和+/- 50 000个新行。mysql view with group by - performance problem

表源:

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 

但是视图的性能(和基本SELECT)是可怕 - 大约需要4秒钟。

所以,我的问题:

1.在一个视图中好主意,在所有使用GROUP BY?如果不是,有什么更好的选择?

2.有没有(我想是的,我不是SQL专家:/)一种方法来优化这个SELECT(改变查询或http_perf_raw_log结构)?

+0

检索大约所有920 MB的数据没有限制是可接受的在4秒内。无论如何,请发布EXPLAIN EXTENDED,并在查询本身(无查看)上运行一个分析器,并将结果回传。 – Pentium10 2011-04-24 20:07:15

回答

0

该视图只是另一个SELECT查询,但抽象出来使查询结果集更容易。如果底层的SELECT速度慢,视图也是如此。在四秒钟内读取和汇总1 GB数据对我来说听起来并不慢。

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分钟/小时,则运行上面的代码。这样它就更像一个缓存。第一次请求缓慢,之后快速。但是除非有人对此感兴趣,否则你不会放慢服务器速度。

+0

我相信交易将无法正常工作。 TRUNCATE无法回滚。 DROP和CREATE表更安全。 – 2016-06-12 09:42:43

+0

@PatrickSavalle:好点:truncate导致一个隐含的提交。不过,我认为你提出的解决方案在innodb表格上不会像预期的那样工作。事务的要点是确保其他会话不会看到任何空表,但innodb表变得直接可见(在插入之前)。最简单的解决方法可能只是“删除”而不是截断。这种情况是关于一个包含汇总数据的表,并且每小时会调用一次,因此我认为drop + create的性能增益可以忽略不计。 – 2016-06-15 00:34:06

+0

将'truncate'更新为'delete' – 2016-06-15 00:36:15

1

从视图中删除GROUP BY和调用VIEWSELECT使用它。