目前我们正在使用三个嵌套的foreach循环来获取运行批处理的信息.但是我很确定我们可以使用带有连接和子查询的单个
MySQL语句来获取信息.
我们有大约30个类别,2000个用户.我们的目标是大约100个类别,拥有100000个用户,但显然foreach循环并不理想(即使现在他们需要大约一分钟才能运行).
环境:
如果可以在特定区域进行交易,则用户希望收到通知
目标:
批量处理(每日,每周等)通知将放入发件箱中
技术:
PHP,MySQL
到目前为止我所拥有的:
数据库:
"table.notification_options" : [id][user_id][category]
"table.user" : [id][user_id][method_of_contact][contact_frequency][center_of_work_area_long][center_of_work_area_lat][distance_from_center]
"table.work" : [id][post_date][longitude][latitude][category]
码:
foreach user{
foreach category tracked{
foreach job in category posted <> $current_date-$batch_frequency{
if job inside workspace{
notify_user(job);
}
}
}
}
所需的结果是以user_id为键的job_id数组数组
[USER_ID] => {作业}
例如
{
[user1]{
job1,
job4,
job28
},
[user34]{
job3,
job4,
job34,
job78
}
{
编辑:
我有一点效率,我可以为一个用户选择所有作业.但它仍然需要一个foreach用户.
$category_id = get_category_from_notification_options($userid);
$user_distance = get_user_work_distance($userid);
"SELECT DISTINCT work.ID as workID, ( 6371 * acos( cos( radians(-46.409939) ) * cos( radians( jobs.lat ) ) * cos( radians( jobs.lng ) - radians(168.366180) ) + sin( radians(-46.409939) ) * sin( radians( jobs.lat ) ) ) )
AS distance
FROM work,user
WHERE work.categoryID == $category_id
HAVING distance < $user_distance
ORDER BY distance";
最佳答案 我认为你应该采取相反的方式来提高效率.下面我将向您展示我用于创建查询的过程.因此,只有最终查询才是您所需要的.但我解释了这些步骤,所以它可能会在将来帮助你.
首先,我会选择所有工作.如果你的目标是100.000个用户,那么很可能用户的工作量会少得多.
select JOB.id, JOB.category
FROM table.work JOB
现在我们已经完成了所有工作,让我们看看哪些用户想要收到通知.
select JOB.id, JOB.category, NOTIFY.user_id
FROM table.work JOB
LEFT JOIN table.notification_options NOTIFY
ON JOB.category=NOTIFY.category
WHERE NOTIFY.user_id IS NOT NULL
这将为每个作业创建一个列表,所有用户ID都希望得到通知.我添加了WHERE子句来删除列表中没有人想要查看的所有作业.
现在我们可以加入users表来获取用户详细信息.
select JOB.id
, JOB.post_date
, JOB.longitude
, JOB.latitude
, USR.user_id
, USR.method_of_contact
, USR.contact_frequency
, USR.center_of_work_area_long
, USR.center_of_work_area_lat
, USR.distance_from_center
, ((ACOS(SIN(USR.center_of_work_area_lat * PI() / 180) * SIN(JOB.latitude * PI() / 180) + COS(USR.center_of_work_area_lat * PI() / 180) * COS(JOB.latitude * PI() / 180) * COS((USR.center_of_work_area_long – JOB.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS `distance`
FROM table.work JOB
LEFT JOIN table.notification_options NOTIFY
ON JOB.category=NOTIFY.category
LEFT JOIN table.user USR
ON NOTIFY.user_id=USR.user_id
WHERE NOTIFY.user_id IS NOT NULL
HAVING `distance`<=USR.distance_from_center
ORDER BY USR.user_id ASC, distance ASC
我在查询中包含了距离.请注意,我使用HAVING检查距离是否小于用户提供的距离.如果要将其添加到WHERE子句中,则会出现错误,指出距离是未知列.
我还添加了ORDER BY类,首先对用户ID进行排序,然后对距离进行排序.这样可以更轻松地在PHP中创建所需的数组.
现在有很多方法可以实现每日/每周间隔.其中之一是为每个间隔创建单独的脚本,并仅选择设置它的用户.
例如,您可以创建一个脚本’daily.php’,您每天运行该脚本并进行以下查询
select JOB.id
, JOB.post_date
, JOB.longitude
, JOB.latitude
, USR.user_id
, USR.method_of_contact
, USR.contact_frequency
, USR.center_of_work_area_long
, USR.center_of_work_area_lat
, USR.distance_from_center
, ((ACOS(SIN(USR.center_of_work_area_lat * PI() / 180) * SIN(JOB.latitude * PI() / 180) + COS(USR.center_of_work_area_lat * PI() / 180) * COS(JOB.latitude * PI() / 180) * COS((USR.center_of_work_area_long – JOB.longitude) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS `distance`
FROM table.work JOB
LEFT JOIN table.notification_options NOTIFY
ON JOB.category=NOTIFY.category
LEFT JOIN table.user USR
ON NOTIFY.user_id=USR.user_id
WHERE NOTIFY.user_id IS NOT NULL
AND USR.contact_frequency = 'daily'
HAVING `distance`<=USR.distance_from_center
ORDER BY USR.user_id ASC, distance ASC
现在我们有了查询,让我们为它创建PHP代码.我们可以循环遍历所有行并创建数组.显然,您也可以直接处理结果,而不是创建数组.因为如果先创建一个数组,那么之后需要再次循环该数组.
<?php
$arNotify = array();
foreach ($queryresult as $row) {
$userid = $row->user_id;
$jobid = $row->id;
//check if there is an entry for the user in the database, else create it
if (!array_key_exists($userid, $arNotify))
$arNotify[$userid] = array();
//and then push the job
$arNotify[$userid][] = $jobid;
//the array is being created, but I still like to process the job directly
//notify_user($userid, $jobid);
}
var_dump($arNotify);
?>
你去,你想要的数组与最接近的工作排序.