我想计算特定月份和日期的订阅者数量,并以表格格式打印。我有 3 个表(registration、registration_session 和 commodity),我想根据更新日期限制为 30 天的商品表中的注册来统计月和日的记录数。我已经给出了解决方案,它工作正常,但打印最终结果需要很多时间。
编辑: 我的计划是打印全年必须发送的 SMS/语音调用详细信息的总数。但不要计算超过 30 天的记录。请检查下面给出的我的 php 代码,您可能会理解我正在尝试做什么。它正在工作,但问题是,它非常慢。完成任务需要将近一个小时。
最终结果:
Sunday Monday Tuesday Wednesday Thursday Friday Saturday
January 17333 15455 15368 16348 14827 15054 14637
February 17332 15481 15400 16351 14824 15059 14613
March 17125 15689 15721 16393 14807 14938 14479
April 18542 17426 17485 17941 16414 16427 15972
May 15824 14870 15044 15441 14311 14485 13861
June 15186 14138 14360 14769 13643 13798 13195
July 13496 12602 12837 13163 12168 12228 11669
August 13305 12333 12570 12891 11913 11974 11422
September 13286 12371 12649 12913 11898 11927 11553
October 12893 11773 11912 12390 11407 11516 11097
November 13563 12415 12516 13042 12028 12173 11764
December 13849 12172 12274 13041 11797 12119 11613
我的问题是,如何让它更快?
我的表格: 注册
id mobile name day state language status
1 1234566532 ishtiyaq 'SUN:MON' up en 1
2 2313443454 sandeep 'MON:TUE' up en 1
3 7436343422 shiv 'MON:TUE:WED' up en 1
registration_session
id reg_id session com distt status
1 1 'JAN:FEB' com1:com2:com3 dist1:dist2:dist3 1
2 1 'DEC:JAN:FEB' com1:com2 dist1:dist2 1
3 2 'APR:MAY:JUN' com4:com6 dist4:dist8 1
商品
id state distt com price date_updated
1 up distt1 com1 200 2015-04-23
2 up distt2 com2 420 2015-12-17
3 up distt4 com3 340 2015-10-16
4 up distt1 com2 560 2015-09-13
5 up distt4 com4 320 2015-11-01
6 mp distt5 com2 322 2015-10-01
7 dl distt7 com5 120 2015-12-11
结果:
|--------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|
| | Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
|--------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|
|January | 9876-14150 | 8533-12026 | 8491-11991 | 9136-13027 | 8196-11581 | 8404-12015 | 8244-11748 |
|--------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|
|Febury | 9845-13450 | 8521-54026 | 5441-13491 | 1136-13217 | 7196-16531 | 8704-12613 | 2244-14748 |
|--------|---------------|---------------|---------------|---------------|---------------|---------------|---------------|
......
我的解决方案:
$arr_months = array('JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC');
$arr_days = array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT');
foreach ($arr_months as $month) {
foreach ($arr_days as $day) {
$total_msg = 0;
$total_rec = 0;
$sql1 = "SELECT registration.mobile,
registration.id,
registration.state,
registration.language,
registration_session.com,
registration_session.distt
FROM registration_session
INNER JOIN registration
ON registration_session.reg_id = registration.id
WHERE registration_session.session LIKE '%" . $month . "%'
AND registration.status = 1
AND registration.language = 'en'
AND registration.day LIKE '%" . $day . "%'
ORDER BY registration.mobile";
$result1 = mysqli_query($con, $sql1);
while ($row1 = mysqli_fetch_assoc($result1)) {
$state = $row1['state'];
$commodity = explode(':', $row1['commodity']);
$distt = explode(':', $row1['distt']);
$count = count($commodity);
$found = false;
while ($count > 0) {
$sql2 = "SELECT * FROM commodity
WHERE date_updated BETWEEN CURDATE() - INTERVAL 30 DAY AND SYSDATE()
AND state = '".$state."'
AND distt = '".$distt[$count - 1]."'
AND cv_commodity = '".$commodity[$count - 1]."'";
$result2 = mysqli_query($con, $sql2);
if (mysqli_num_rows($result2) > 0) {
$total_msg++;
$found = true;
}
$count--;
}
if ($found == true) {
$total_rec++;
}
}
}
}
--
-- Table structure for table `commodity`
--
CREATE TABLE IF NOT EXISTS `commodity` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`state` varchar(100) NOT NULL,
`distt` varchar(100) NOT NULL,
`com` varchar(100) NOT NULL,
`price` int(10) NOT NULL,
`date_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
建表语句:
CREATE TABLE IF NOT EXISTS `registration` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`mobile` int(10) DEFAULT NULL,
`name` varchar(22) NOT NULL,
`day` varchar(255) NOT NULL,
`state` varchar(50) NOT NULL,
`language` varchar(2) NOT NULL,
`status` int(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `registration_session` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`reg_id` int(10) DEFAULT NULL,
`session` varchar(255) NOT NULL,
`com` varchar(255) NOT NULL,
`distt` varchar(50) NOT NULL,
`status` int(1) NOT NULL,
PRIMARY KEY (`id`),
KEY `reg_id` (`reg_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `commodity` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`state` varchar(100) NOT NULL,
`distt` varchar(100) NOT NULL,
`com` varchar(100) NOT NULL,
`price` int(10) NOT NULL,
`date_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
最佳答案
如果我没看错你的循环,这个脚本就会对数据库进行大量调用。第一个查询是 weekdays * months(84 个查询),然后是这 84 个循环中每个循环的状态、商品和 distt 的所有可能组合。
我建议一次获取两个查询的所有结果,然后循环遍历 PHP 中的记录,以按月、日和州、商品和 Distt 形成结果。
如果您不需要那种级别的粒度,我也会汇总您的查询。在第一个示例中:
SELECT
registration.day,
registration.mobile,
registration.id,
registration.state,
registration.language,
registration_session.com,
registration_session.session,
registration_session.distt,
COUNT(1) AS cnt
FROM
registration_session
INNER JOIN
registration ON registration_session.reg_id = registration.id
WHERE
AND registration.status = 1
AND registration.language = 'en'
GROUP BY
registration.day,
registration.mobile,
registration.id,
registration.state,
registration.language,
registration_session.com,
registration_session.session,
registration_session.distt
商品一:
SELECT
state,
distt,
cv_commodity,
COUNT(1) AS cnt
FROM
commodity
WHERE
date_updated BETWEEN CURDATE() - INTERVAL 30 DAY AND SYSDATE()
GROUP BY
state,
distt,
cv_commodity
然后您的 PHP 循环遍历结果:
$arr_months = array('JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC');
$arr_days = array('SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT');
foreach ($arr_months as $month) {
foreach ($arr_days as $day) {
$total_msg = 0;
$total_rec = 0;
foreach ($result1 AS $row1) {
if (strpos($row1['session'],$month) !== false AND strpos($row1['day'],$day) !== false){
$state = $row1['state'];
$commodity = explode(':', $row1['com']);
$distt = explode(':', $row1['distt']);
#$count = number of commodities * number of records in db for this row
$count = count($commodity) * $row1['cnt'];
#Check if State/Commodity exist in $result2 using the same strpos method above
#Store aggregates for each month/day in a new array to display results
}
}
}
}
我会采用这种方法来优化性能,方法是减少数据库查询的数量,汇总结果,从而减少需要预先加载到内存中的记录,然后循环获取我的结果。
关于php - 根据用户订阅计算月和日的记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34559239/