GROUP BY查询 - 为什么这么慢

时间:2013-02-05 14:31:28

标签: mysql group-by

我正在尝试在一个大表(超过800万行)上生成一个组查询。但是,我可以减少按日期对所有数据进行分组的需要。我有一个视图,捕获我需要的日期,这限制了查询,它不是更好。 最后,我需要加入另一个表来接收一个字段。

我正在显示查询,主表上的创建和下面的查询说明。

主要查询:

SELECT  pgi_raw_data.wsp_channel,
        'IOM' AS wsp,
        pgi_raw_data.dated,
        pgi_accounts.`master`,
        pgi_raw_data.event_id,
        pgi_raw_data.breed,
        Sum(pgi_raw_data.handle),
        Sum(pgi_raw_data.payout),
        Sum(pgi_raw_data.rebate),
        Sum(pgi_raw_data.profit)
FROM    pgi_raw_data
        INNER JOIN summary_max
                ON pgi_raw_data.wsp_channel = summary_max.wsp_channel
                        AND pgi_raw_data.dated > summary_max.race_date
        INNER JOIN pgi_accounts
                ON pgi_raw_data.account = pgi_accounts.account
GROUP   BY pgi_raw_data.event_id
ORDER   BY NULL

创建表:

 CREATE TABLE `pgi_raw_data` (
  `event_id` char(25) NOT NULL DEFAULT '',
  `wsp_channel` varchar(5) NOT NULL,
  `dated` date NOT NULL,
  `time` time DEFAULT NULL,
  `program` varchar(5) NOT NULL,
  `track` varchar(25) NOT NULL,
  `raceno` tinyint(2) NOT NULL,
  `detail` varchar(30) DEFAULT NULL,
  `ticket` varchar(20) NOT NULL DEFAULT '',
  `breed` varchar(12) NOT NULL,
  `pool` varchar(10) NOT NULL,
  `gross` decimal(11,2) NOT NULL,
  `refunds` decimal(11,2) NOT NULL,
  `handle` decimal(11,2) NOT NULL,
  `payout` decimal(11,4) NOT NULL,
  `rebate` decimal(11,4) NOT NULL,
  `profit` decimal(11,4) NOT NULL,
  `account` mediumint(10) NOT NULL,
  PRIMARY KEY (`event_id`,`ticket`),
  KEY `idx_account` (`account`),
  KEY `idx_wspchannel` (`wsp_channel`,`dated`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

这是我对summary_max的看法:

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW 
 `summary_max` AS select `pgi_summary_tbl`.`wsp_channel` AS 
 `wsp_channel`,max(`pgi_summary_tbl`.`race_date`) AS `race_date` 
from `pgi_summary_tbl` group by `pgi_summary_tbl`.`wsp

还有评估的查询:

1   PRIMARY <derived2>  ALL                 6   Using temporary

1   PRIMARY pgi_raw_data    ref idx_account,idx_wspchannel  idx_wspchannel  
7   summary_max.wsp_channel 470690  Using where

1   PRIMARY pgi_accounts    ref PRIMARY PRIMARY 3   gf3data_momutech.pgi_raw_data.account   29  Using index

2   DERIVED pgi_summary_tbl ALL                 42282   Using temporary; Using filesort

任何有关索引的帮助都会有所帮助。

2 个答案:

答案 0 :(得分:0)

至少您需要这些字段的索引:

pgi_raw_data.wsp_channel,
pgi_raw_data.dated,  
pgi_raw_data.account
pgi_raw_data.event_id,
summary_max.wsp_channel, 
summary_max.race_date, 
pgi_accounts.account

一般(并非总是)规则是您要排序,分组,过滤或加入的任何内容都应该有索引。

另外:pgi_summary_tbl.wsp

另外,为什么order by null

答案 1 :(得分:0)

首先要确保您在pgi_summary_table(wsp_channel, race_date)pgi_accounts(account).上有索引。对于此查询,您不需要原始数据中这些列的索引。

即使MySQL不是最有效的路径,它也倾向于使用索引。我首先看一下“完整”查询的性能,没有连接:

SELECT  pgi_raw_data.wsp_channel,
        'IOM' AS wsp,
        pgi_raw_data.dated,
        -- pgi_accounts.`master`,
        pgi_raw_data.event_id,
        pgi_raw_data.breed,
        Sum(pgi_raw_data.handle),
        Sum(pgi_raw_data.payout),
        Sum(pgi_raw_data.rebate),
        Sum(pgi_raw_data.profit)
FROM    pgi_raw_data
GROUP   BY pgi_raw_data.event_id

如果这有更好的性能,您可能会遇到索引对您不利的情况。具体问题称为“颠簸”。当表太多而无法放入内存时会发生这种情况。通常,处理这样一个表的最快方法就是阅读整个事情。通过索引访问表可能会导致大多数行的额外I / O操作。

如果这样做,那么在聚合之后进行连接。另外,考虑获得更多内存,因此整个表格将适合内存。

其次,如果你必须处理这种类型的数据,那么按日期对表进行分区可能是一个非常有用的选择。这将允许您显着减少读取大表的开销。您必须确保可以以相同的方式读取摘要表。