mysql视图与group by - 性能问题

时间:2011-04-24 17:03:01

标签: mysql performance select view

我有一个收集网页性能数据的表格。有多台机器,以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的查询或结构)?

3 个答案:

答案 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数据对我来说听起来并不慢。