背景:
首先,我有一个模式,其中有一个名为patients
我关心的表,patient_id
并且alerts
(警报是一串字符,其中每个字符代表一些任意值/含义)。其次,每个“患者”都是一个组 [family] 的一部分,仅基于他们的 patient_id 上的前 6 位数字。此外,还有一些第三方依赖此数据库;我没有设计,也无法更改此架构/数据模型,也无法从 MySQL 迁移。
挑战:
现在,我需要找出患者有包含!
、@
、#
、%
、^
或&
符号的警报而他们的家庭成员没有的事件。我的第一个想法是收集所有具有包含这些符号的警报的患者,删除每个患者 ID 中的最后一位数字,然后按此值分组。现在我有一个(出于所有意图和目的)“group_ids”的列表。最后,我需要扩展列表以包含每个组的家庭成员及其各自的警报字符串。
这是我到目前为止所拥有的:
查询 #1:
SELECT p.patient_id, p.name_first, p.name_last, p.alerts
FROM patients p
INNER JOIN (SELECT SUBSTRING(patient_id, 1, CHAR_LENGTH(patient_id) - 1) AS group_id
FROM patients
WHERE patient_id BETWEEN 1000000 AND 7999999
AND (alerts like '%!%'
OR alerts like '%@%'
OR alerts like '%#%'
OR alerts like '%\%%'
OR alerts like '%^%'
OR alerts like '%&%')
GROUP BY group_id) g
ON p.patient_id LIKE CONCAT(g.group_id, '%')
ORDER BY p.patient_id
LIMIT 30000;
Fiddle ~注意: fiddle 不是问题的准确表示,因为包含的表只有 28 条记录。
记录集:80,000 ~ 结果:2188 ~ 持续时间:14.321 秒 ~ 获取:0.00 秒 ~ 总计:14.321 秒
查询 #2:
SELECT p.patient_id, p.name_first, p.name_last, p.alerts
FROM patients p
JOIN (SELECT DISTINCT LEFT(patient_id, 6) AS group_id
FROM patients
WHERE patient_id BETWEEN 1000000 AND 7999999
AND alerts REGEXP '[!@#%^&]') g
ON p.patient_id LIKE CONCAT(g.group_id, '%')
ORDER BY p.patient_id
LIMIT 30000;
Fiddle ~注意: fiddle 不是问题的准确表示,因为包含的表只有 28 条记录。
记录集:80,000 ~ 结果:2188 ~ 持续时间:4.259 秒 ~ 获取:5.663 秒 ~ 总计:9.992 秒
编辑:添加 name_first、name_last、alerts 和 order by 子句后,我发现此查询与第一个查询所用的时间完全相同。
问题:
我得到的列表是准确的,但是不仅需要额外的处理(我打算用 PHP 来做),而且需要 14 秒!
如果有人有更好的......或者至少可以指出一个更好、更有效的解决方案的方向,请赐教。提前致谢。
额外的信用:任何关于 PHP 算法的技巧,以解决给定数据的上述问题 - 忘记语义,只需一个公式即可。