我在从大量MySQL数据库中获取数据时遇到问题。
使用以下代码,可以获得10K患者和5K预约的列表,这是我们的测试服务器。
但是,在我们的实时服务器上,患者人数超过100K,约会次数超过300K,一段时间后我运行代码时出现500错误。
我需要患者列表,患者的治疗时间为1或3,并且在他们上次预约后一个月内没有预约。 (以下代码适用于少量患者和预约)
如何优化第一个数据库查询,以便在foreach循环中不需要第二个数据库查询?
<?php
ini_set('memory_limit', '-1');
ini_set('max_execution_time', 0);
require_once('Db.class.php');
$patients = $db->query("
SELECT
p.id, p.first_name, p.last_name, p.phone, p.mobile,
LatestApp.lastAppDate
FROM
patients p
LEFT JOIN (SELECT patient_id, MAX(start_date) AS lastAppDate FROM appointments WHERE appointment_status = 4) LatestApp ON p.id = LatestApp.patient_id
WHERE
p.patient_treatment_status = 1 OR p.patient_treatment_status = 3
ORDER BY
p.id
");
foreach ($patients as $row) {
$one_month_after_the_last_appointment = date('Y-m-d', strtotime($row['lastAppDate'] . " +1 month"));
$appointment_check = $db->single("SELECT COUNT(id) FROM appointments WHERE patient_id = :pid AND appointment_status = :a0 AND (start_date >= :a1 AND start_date <= :a2)", array("pid"=>"{$row['id']}","a0"=>"1","a1"=>"{$row['lastAppDate']}","a2"=>"$one_month_after_the_last_appointment"));
if($appointment_check == 0){
echo $patient_id = $row['id'].' - '.$row['lastAppDate'].' - '.$one_month_after_the_last_appointment. '<br>';
}
}
?>
答案 0 :(得分:1)
首先,这个子查询可能不会按照你的想法做到。
SELECT patient_id, MAX(start_date) AS lastAppDate
FROM appointments WHERE appointment_status = 4
如果没有GROUP BY子句,该子查询将只使用start_date
获取所有约会的最大appointment_status=4
,然后随意选择一个patient_id
。要获得您想要的结果,您需要GROUP BY patient_id
。
对于您的整体问题,请尝试以下查询:
SELECT
p.id, p.first_name, p.last_name, p.phone, p.mobile,
LatestApp.lastAppDate
FROM
patients p
INNER JOIN (
SELECT patient_id,
MAX(start_date) AS lastAppDate
FROM appointments
WHERE appointment_status = 4
GROUP BY patient_id
) LatestApp ON p.id = LatestApp.patient_id
WHERE
(p.patient_treatment_status = 1
OR p.patient_treatment_status = 3)
AND NOT EXISTS (
SELECT 1
FROM appointments a
WHERE a.patient_id = p.patient_id
AND a.appointment_status = 1
AND a.start_date >= LatestApp.lastAppDate
AND a.start_date < DATE_ADD(LatestApp.lastAppDate,INTERVAL 1 MONTH)
)
ORDER BY
p.id
添加以下索引(如果它尚不存在):
ALTER TABLE appointments
ADD INDEX (`patient_id`, `appointment_status`, `start_date`)
报告其执行情况以及数据是否正确。提供SHOW CREATE TABLE patient
和SHOW CREATE TABLE appointments
以获得与效果相关的进一步帮助。
此外,尝试上面的查询,不带AND NOT EXISTS
子句,以及您使用的第二个查询。在这种情况下,运行2个查询可能比尝试一起运行更快。
请注意,我使用INNER JOIN
来查找最新约会。这将导致所有从未预约的患者不被包括在查询中。如果您需要添加这些,只需通过从未预约过的患者中进行选择来获得结果。