将SQL WHERE IN转换为JOIN

时间:2014-01-12 15:52:50

标签: mysql sql

我有一个存储有关虚构人物的各种信息的数据库。有一个桌面人员提供一般信息,如姓名,地址等,以及一些更具体的表格,包含健康历史和每个人的教育。 我现在要做的是,根据相似之处,例如同时在同一所学校或同一位医生或同时在同一家医院接受治疗,可以为一个人建立可能的联系。

以下查询可以正常工作(:id是相关人员的ID),但速度非常慢(大约需要6秒才能获得结果)。

SELECT person.p_id as id, fname, lname, image FROM person WHERE 
                (person.p_id IN (
                    SELECT patient from health_case WHERE 
                        doctor IN (SELECT doctor FROM health_case WHERE patient =:id ) 
                        OR center IN (SELECT hc2.center FROM health_case as hc1, health_case as hc2 WHERE hc1.patient = :id AND hc2.center = hc1.center AND (hc1.start <= hc2.end AND hc1.end >= hc2.start)))
                OR person.p_id IN (
                    SELECT ed2.pupil FROM education as ed1, education as ed2 WHERE 
                        ed1.school IN (SELECT school FROM education WHERE pupil = :id) AND ed2.school = ed1.school AND (ed2.start <= ed1.end AND ed2.end >= ed1.start)
                )) 
                AND person.p_id != :id

将它转换为使用JOIN子句的最佳方法是什么?我似乎无法绕过这些......

2 个答案:

答案 0 :(得分:2)

我想我明白你要做什么。皮肤猫的方法不止一种,但我是否可以建议将查询拆分为两个单独的查询,然后用一对内连接替换复杂的WHERE子句?所以,像这样:

/* Find connections based on health care */
SELECT p2.p_id as id, p2.fname, p2.lname, p2.image
FROM person p
JOIN health_case hc on hc.patient = p.p_id
JOIN health_case hc2 on hc2.doctor = hc.doctor and hc2.healthcenter = hc.healthcenter and hc.start <= hc2.end and hc.end >= hc2.start and hc2.patient <> hc.patient
JOIN person p2 on p2.p_id = hc2.patient and p2.p_id <> p.p_id
WHERE p.p_id = :id

然后,创建一个单独的查询以根据教育获得连接:

/* Find connections based on education */
SELECT p2.p_id as id, p2.fname, p2.lname, p2.image
FROM person p
JOIN education e on e.pupil = p.p_id
JOIN education e2 on e2.school = e.school and e2.start <= e.end AND e2.end >= e.start and e.pupil <> e2.pupil
JOIN person p2 on p2.p_id = e2.pupil and p2.p_id <> p.p_id
WHERE p.p_id = :id

如果您真的希望合并数据结果,可以使用UNION,因为两个查询都会从人员表中返回相同的列。

答案 1 :(得分:0)

取决于您的SQL引擎。具有合理查询优化器的较新SQL系统很可能会将IN和JOIN查询重写为同一计划。通常,使用连接重写子查询(IN子句)。

在可能没有很好的查询优化器的简单SQL引擎中,连接应该更快,因为它们可以在运行外部查询之前将子查询运行到临时内存表中。

在一些内存占用有限的SQL引擎中,子查询可能更快,因为它不需要加入 - 这会产生更多数据。