2014-04-04 34 views
0

我运行一个更新语句:如何使用子查询优化更新语句?

UPDATE ACTION a 
INNER JOIN subscriberinfo s ON a.subscriberId=s.id 
SET a.exceedusage = (SELECT FORMAT(((SUM(dataVolumeDownLink + dataVolumeUpLink))/1048576),2) 
      FROM cdr c 
      WHERE c.msisdn=s.msisdn 
      AND c.eventDate>=a.createdon 
      AND c.eventDate <= a.actionTakenOn) 
WHERE a.remark='Reason : Data limit crossed' 
AND a.exceedusage IS NULL; 

但其采取CDR,因为表(百万行)的时间太多。有什么方法可以重写此查询,以便它可以快速工作?

编辑:行动

表结构:

CREATE TABLE `action` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `actionTakenOn` datetime DEFAULT NULL, 
    `actionType` varchar(255) DEFAULT NULL, 
    `cdrCreatedOn` datetime DEFAULT NULL, 
    `cdrEventDate` datetime DEFAULT NULL, 
    `createdOn` datetime DEFAULT NULL, 
    `errorDescription` longtext, 
    `params` longtext, 
    `remark` longtext, 
    `requestedOn` datetime DEFAULT NULL, 
    `status` varchar(255) DEFAULT NULL, 
    `subscriberDetails` longtext, 
    `takenBy` varchar(255) DEFAULT NULL, 
    `subscriberId` bigint(20) DEFAULT NULL, 
    `ticketId` bigint(20) DEFAULT NULL, 
    `dataPlanEndTime` datetime DEFAULT NULL, 
    `dataPlanStartTime` datetime DEFAULT NULL, 
    `dataUsage` bigint(20) DEFAULT NULL, 
    `dataplanName` varchar(255) DEFAULT NULL, 
    `exceedUsage` bigint(20) DEFAULT NULL, 
    `isNotified` bit(1) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `FKAB2F7E36E90F678D` (`subscriberId`), 
    KEY `FKAB2F7E3664633B07` (`ticketId`) 
) ENGINE=MyISAM AUTO_INCREMENT=81534 DEFAULT CHARSET=latin1; 

为Subscriberinfo:

CREATE TABLE `subscriberinfo` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `imsi` varchar(255) DEFAULT NULL, 
    `simType` varchar(45) DEFAULT NULL, 
    `dataPlanStartTime` datetime DEFAULT NULL, 
    `dataPlanEndTime` datetime DEFAULT NULL, 
    `dataplan` varchar(255) DEFAULT NULL, 
    `status` varchar(255) DEFAULT NULL, 
    `validDays` varchar(255) DEFAULT NULL, 
    `deviceName` varchar(500) DEFAULT NULL, 
    `lastDataPlanUpdatedOn` datetime DEFAULT NULL, 
    `lastDeviceUpdatedOn` datetime DEFAULT NULL, 
    `createdOn` datetime DEFAULT NULL, 
    `dataplanType` varchar(255) DEFAULT NULL, 
    `msisdn` bigint(20) DEFAULT NULL, 
    `dataLeft` bigint(20) DEFAULT NULL, 
    `billingSysDataPlanEndTime` datetime DEFAULT NULL, 
    `billingSysDataPlanStartTime` datetime DEFAULT NULL, 
    `billingSysValidDays` int(11) DEFAULT NULL, 
    `dataUsage` bigint(20) DEFAULT NULL, 
    `planDetail` varchar(255) DEFAULT NULL, 
    `currentSpeedLimit` varchar(255) DEFAULT NULL, 
    `lastBillingSysUpdatedOn` datetime DEFAULT NULL, 
    `lastUpdatedOn` datetime DEFAULT NULL, 
    `deviceType` varchar(255) DEFAULT NULL, 
    `lastImsiUpdatedOn` datetime DEFAULT NULL, 
    `skipCheck` tinyint(1) NOT NULL, 
    `active` tinyint(1) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `msisdn_UNIQUE` (`msisdn`) 
) ENGINE=InnoDB AUTO_INCREMENT=49032 DEFAULT CHARSET=latin1; 

为CDR:

CREATE TABLE `cdr` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `dataPacketDownLink` bigint(20) DEFAULT NULL, 
    `dataPacketUpLink` bigint(20) DEFAULT NULL, 
    `dataPlanEndTime` datetime DEFAULT NULL, 
    `dataPlanStartTime` datetime DEFAULT NULL, 
    `dataVolumeDownLink` bigint(20) DEFAULT NULL, 
    `dataVolumeUpLink` bigint(20) DEFAULT NULL, 
    `dataplan` varchar(255) DEFAULT NULL, 
    `dataplanType` varchar(255) DEFAULT NULL, 
    `createdOn` datetime DEFAULT NULL, 
    `deviceName` varchar(500) DEFAULT NULL, 
    `duration` int(11) NOT NULL, 
    `effectiveDuration` int(11) NOT NULL, 
    `hour` int(11) DEFAULT NULL, 
    `eventDate` datetime DEFAULT NULL, 
    `msisdn` bigint(20) DEFAULT NULL, 
    `quarter` int(11) DEFAULT NULL, 
    `validDays` int(11) DEFAULT NULL, 
    `dataLeft` bigint(20) DEFAULT NULL, 
    `completedOn` datetime DEFAULT NULL, 
    `causeForRecClosing` bigint(20) DEFAULT NULL, 
    `roaming` tinyint(1) DEFAULT NULL, 
    `servedBSAddress` varchar(255) DEFAULT NULL, 
    `simType` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `idx_msisdn` (`msisdn`) 
) ENGINE=MyISAM AUTO_INCREMENT=2580713 DEFAULT CHARSET=latin1; 
+0

的任何输出EXPLAIN上上述查询的选择?表结构?指标? – blue

回答

2
UPDATE ACTION a 
    INNER JOIN subscriberinfo s ON a.subscriberId=s.id 
    INNER JOIN (SELECT FORMAT(((SUM(dataVolumeDownLink + dataVolumeUpLink))/1048576),2) as val, 
        msisdn 
        FROM cdr c 
        WHERE 
        c.eventDate>=a.createdon 
        AND c.eventDate <= a.actionTakenOn) sub on sub.msisdn=s.msisdn 
SET a.exceedusage = sub.val 
WHERE a.remark='Reason : Data limit crossed' 
AND a.exceedusage IS NULL; 

我会将子查询移动到FROM(实际上是FROM中的SELECT和UPDATE部分中的查询),让它只执行一次。

+0

@ StanislavL-谢谢你的帮助,但请解释一下,如果可能的话,为什么在内部连接中复制相同内容? – Aamir

+1

为了避免重新计算每个更新的值。在你的情况下,查询是为每一行执行的。 – StanislavL

+0

我收到以下错误.. 错误代码:1054 运行此查询时,'where子句' 中的未知列'a.createdon'。如何删除它? – Aamir

0

可能将整个事情改为一系列JOIN。

这不能不说是一个猜测(我不知道你的表是如何团结在一起,因此不能确定在GROUP BY),但也许是这样的: -

UPDATE ACTION a 
INNER JOIN subscriberinfo s ON a.subscriberId=s.id 
INNER JOIN cdr c ON c.msisdn=s.msisdn AND c.eventDate BETWEEN a.createdon AND a.actionTakenOn 
SET a.exceedusage = FORMAT(((SUM(c.dataVolumeDownLink + c.dataVolumeUpLink))/1048576),2) 
WHERE a.remark='Reason : Data limit crossed' 
AND a.exceedusage IS NULL 
GROUP BY a.subscriberId;