Sql Query使用group by花费太多时间

时间:2014-12-04 17:05:09

标签: mysql sql

今天我有一张包含5米记录的表。到这个数据将增加到1或20亿条记录。我的任务是根据此数据生成摘要报告,为此我使用以下查询。

SELECT creation_date
    ,caller_circle
    ,count(id)
FROM call_reporting
WHERE enterprise_id = 206
GROUP BY DATE (creation_date)
    ,caller_circle limit 10;

表结构如下所示。

CREATE TABLE `call_reporting` (
  `ID` bigint(20) NOT NULL AUTO_INCREMENT,
  `SESSION_ID` varchar(255) DEFAULT NULL,
  `CALLER_NUMBER` bigint(20) NOT NULL,
  `DIALED_NUMBER` bigint(20) NOT NULL,
  `CALL_START_TIME` datetime DEFAULT NULL,
  `CALL_END_TIME` datetime DEFAULT NULL,
  `OUT_CALL_START_TIME` datetime DEFAULT NULL,
  `OUT_CALL_END_TIME` datetime DEFAULT NULL,
  `HUNTING_START_TIME` datetime DEFAULT NULL,
  `IN_CALL_DURATION` bigint(20) DEFAULT NULL,
  `OUT_CALL_DURATION` bigint(20) DEFAULT NULL,
  `HUNTING_DURATION` bigint(20) DEFAULT NULL,
  `ADV_ID` bigint(20) DEFAULT NULL,
  `ENTERPRISE_ID` bigint(20) DEFAULT NULL,
  `AGENT_ID` bigint(20) DEFAULT NULL,
  `HUNT_TRY` int(255) DEFAULT NULL,
  `CAMPAIGN_ID` bigint(20) DEFAULT NULL,
  `CALL_STATUS` varchar(255) DEFAULT NULL,
  `URL_CALLING_STATUS` varchar(255) DEFAULT NULL,
  `REMARKS` text,
  `REF_NO` varchar(255) DEFAULT NULL,
  `POST_CALL_RESULT` bit(1) DEFAULT NULL,
  `CREATION_DATE` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `AGENT_DIAL_OUT_NUMBER` bigint(20) DEFAULT NULL,
  `DATA_SYNC` bit(1) DEFAULT NULL,
  `CALLER_CIRCLE` varchar(50) DEFAULT NULL,
  `STATUS_CODE` varchar(50) DEFAULT NULL,
  `OPERATOR_NAME` varchar(50) DEFAULT NULL,
  `OBD_RESULT_STATUS` bit(1) DEFAULT NULL,
  `MAIL_SENT` bit(1) DEFAULT NULL,
  `SDR_ID` varchar(255) DEFAULT NULL,
  `KEY_PRESS` varchar(1024) DEFAULT NULL,
  `ENTERPRISE_USER_ID` bigint(20) DEFAULT NULL,
  `CAMAIGN_NAME` varchar(128) DEFAULT NULL,
  `DND_NO` bit(1) DEFAULT b'0',
  KEY `ID` (`ID`),
  KEY `ENTERPRISE_ID` (`ENTERPRISE_ID`),
  KEY `SDR_ID` (`SDR_ID`),
  KEY `CALLER_NUMBER` (`CALLER_NUMBER`),
  KEY `CREATION_DATE` (`CREATION_DATE`),
  KEY `DIALED_NUMBER` (`DIALED_NUMBER`),
  KEY `CALLER_CIRCLE` (`CALLER_CIRCLE`),
  KEY `CAMAIGN_NAME` (`CAMAIGN_NAME`),
  KEY `ADV_ID` (`ADV_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2612658 DEFAULT CHARSET=latin1
/*!50100 PARTITION BY HASH (MONTH(CREATION_DATE))
PARTITIONS 12 */ |

此表也包含分区。但是当我运行给定的查询时,需要

10 rows in set (15.11 sec)

当我看到查询配置文件时,它会给出以下统计信息。

+--------------------------------+-----------+
| Status                         | Duration  |
+--------------------------------+-----------+
| starting                       |  0.000052 |
| Waiting for query cache lock   |  0.000017 |
| checking query cache for query |  0.000106 |
| checking permissions           |  0.000023 |
| Opening tables                 |  0.000051 |
| System lock                    |  0.000035 |
| Waiting for query cache lock   |  0.000015 |
| init                           |  0.000085 |
| optimizing                     |  0.000036 |
| statistics                     |  0.003924 |
| preparing                      |  0.000075 |
| Creating tmp table             |  0.000077 |
| executing                      |  0.000014 |
| Copying to tmp table           | 16.945653 |
| Sorting result                 |  0.000879 |
| Sending data                   |  0.001254 |
| end                            |  0.000012 |
| removing tmp table             |  0.000017 |
| end                            |  0.000010 |
| query end                      |  0.000013 |
| closing tables                 |  0.000019 |
| freeing items                  |  0.000030 |
| logging slow query             |  0.000008 |
| logging slow query             |  0.000008 |
| cleaning up                    |  0.000007 |
+--------------------------------+-----------+
25 rows in set (0.01 sec)

将数据复制到临时表中需要花费两倍的时间;有没有办法减少执行时间。在我的情况下临时表大小是

 tmp_table_size                         | 16777216 |

我还在考虑将数据加载到RAM中。但不要有它的利弊。因为在我的情况下数据大小会增长扩展。请给出一个方法来做到这一点。

提前致谢。

1 个答案:

答案 0 :(得分:0)

尝试在

上创建覆盖索引

(enterprise_id,creation_date,caller_circle)

这样,WHERE子句由ID优化,GROUP BY也可以从索引中使用。

此外,更改" count(ID)"只是" count(*)"所以引擎不必去页面获取ID,它只知道覆盖索引中的合格记录。

然后我会建议创建一个辅助表,其中包含给定企业,日期和调用者圈的简单聚合汇总。那就是......如果原始数据不会历史性地改变(例如回填呼叫数据)。它发生了,它完成了,总计是他们的历史日期。然后,如果需要重新校准任何东西,你可以逐步重建,例如一个月/一年,这样你就不会在未来通过十亿条记录。