mysql - 如何使用子查询优化更新语句?

标签 mysql sql performance subquery updates

我正在运行更新语句:

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 表(数百万行),它花费了太多时间。有什么方法可以重写这个查询,以便它可以快速运行吗?

编辑:

Action的表结构:

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;

订阅者信息:

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;

最佳答案

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(实际上是查询的 select 和 UPDATE 部分中的 FROM),以使其仅执行一次。

关于mysql - 如何使用子查询优化更新语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22858098/

相关文章:

sql - 如何进行条件连接

sql - 非常慢的sql插入查询

oracle - 为什么从 Oracle 外部表返回数据这么慢?

java - JPA - 为什么我在数据库中的每一行看到两个实体实例?

mysql - SQL 查询连接无法正常工作

php - 从两个表中选择并按时间戳排序

java - 为什么显示 "No database Selected"SQLException

php - 如何将不同的元素关联到一对多的类别?

sql - Azure SQL DB 存在性能问题,100% log/io 的原因是什么?

mysql - 在 MySQL 中寻找合作