免责声明:我知道我的代码中已经弃用了mysql函数。那是在我的 todo 列表中。
我有一个MySql选择,在房屋预订系统中为我提供不同项目的季节。
种类:
Low season: 2010-01-01, 2010-03-01, 100 //meaning start,end,price
这是我的第一个sql:
while($season_row=mysql_fetch_assoc($season_res)){
$seasonsArray[$season_row['id_item']][] = array(
$season_row['season_start'],
$season_row['season_end'],
$season_row['daily_price']
);
}
这里定义的日期(到达YYYY-mm-dd
的功能):
function seasonPrice($from,$to,$requested_item){
$start = round(strtotime($from)/86400)*86400; // like 2008-01-01
$end = round(strtotime($to)/86400)*86400; // to 2015-01-01
$formattedStart = date('Y-m-d', $start);
$formattedEnd = date('Y-m-d', $end);
现在我需要在$seasonsArray
的项目之间循环2个日期,然后检查该特定日期内该项目的价格。
我是这样做的:
foreach($seasonsArray as $item=>$value){
for( $thisDay = $start; $thisDay < $end; $thisDay = $thisDay + 86400){
foreach($value as $innerValue){
$season_start = roundToSeconds($innerValue[0]);
$season_end = roundToSeconds($innerValue[1]);
if($thisDay >= $season_start && $thisDay <= $season_end) {
$foundPrice[] = round($innerValue[2]);
}
}
$thisSerie[] = array($thisDay * 1000, isset($foundPrice) ? $foundPrice[0] : 0);
// security check to avoid double assigned seasons to same day
if(count($foundPrice) > 1){ die('There is double bookings in item: '.$item);}
unset($foundPrice);
}
$seasonPrices[] = array(
'data'=> $thisSerie,
'label'=> 'House ID: '.$item,
);
}
但我明白了:Fatal error: Allowed memory size of 100663296 bytes exhausted
有关我的代码可以改进到何处不需要这么多内存的任何建议吗?或者是否有错误,我看不到它?
答案 0 :(得分:2)
我会生成一系列天数并加入您的季节表,并使用单个查询来获得所需的结果集,例如:
SELECT dates.Date,
coalesce(s.price, 0) AS price
FROM
(SELECT a.Date
FROM
( SELECT curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY AS Date, '0' AS price
FROM
(SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS a
CROSS JOIN
(SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS b
CROSS JOIN
(SELECT 0 AS a
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 8
UNION ALL SELECT 9) AS c) a
WHERE a.Date BETWEEN '$from' AND '$to'
ORDER BY a.Date) dates
LEFT JOIN seasons s ON dates.Date BETWEEN s.start AND s.END
复杂的内部查询避免创建临时表(取自generate days from date range)并且最多可以工作1000天,但是创建临时表就可以了。
答案 1 :(得分:0)
看起来好像你永远不会离开for循环。 $ start和$ end的设置在哪里。通过打印出来验证它们的值。
就优化而言,没有必要每天循环。跳过计算天数的for循环,并使用$ season_start和$ season_end计算第二个foreach循环中的日期。
事实上,现在有一个bug,除非$ session_start和$ session_end总是超过一天,因为有时候事件会发生在你循环的24小时之间。