我有一个(简化的)查询,如下:
SELECT DISTINCT this_.person_id AS y0_
FROM coded_entity this_
WHERE this_.code = ?
AND this_.tenant_id = ?
AND this_.person_id IN (SELECT person_id
FROM person that
WHERE that.date_voided IS NULL
AND that.ssn = ?
AND that.tenant_id = ? )
我希望能够强制Oracle始终首先执行最里面的子查询,因为我知道它总是会更具选择性。代码只有几个值,而ssn有更多的值。每个表都有相同的行数。
但是,在实际操作中,有时Oracle CBO会决定先执行coded_entity查询,导致时间慢得多。
有没有办法强制执行此操作而不将查询拆分为单独的调用?
答案 0 :(得分:1)
我的第一个念头(无论是否有钥匙)都是这样想的:
SELECT DISTINCT this_.person_id AS y0_
FROM coded_entity this_
WHERE this_.code = ?
AND this_.tenant_id = ?
AND EXISTS (SELECT null
FROM person THAT_
WHERE THAT_.date_voided IS NULL
AND THAT_.ssn = ?
AND THAT_.tenant_id = this_.tenant_id
AND THAT_.person_id = this_.person_id)
但更好的方法(如果person_id是人的关键,并且每个人都有零个或多个编码实体)将是这样的:
SELECT this_.person_id AS y0_
FROM person_ this_
WHERE this_.ssn = ?
AND this_.tenant_id = ?
AND this_.date_voided is null
AND EXISTS (SELECT null
FROM coded_entity THAT_
WHERE THAT_.code = ?
AND THAT_.tenant_id = this_.tenant_id
AND THAT_.person_id = this_.person_id)
答案 1 :(得分:0)
不需要子查询。只需INNER JOIN
并过滤唯一记录。让优化器更好地理解它。
SELECT DISTINCT this_.person_id AS y0_
FROM coded_entity this_
INNER JOIN person that ON this_.person_id = that.person_id
AND this_.tenant_id = that.tenant_id
AND that.date_voided IS NULL
AND that.ssn = ?
WHERE this_.code = ?
AND this_.tenant_id = ?
答案 2 :(得分:0)
您始终可以重写脚本以使条件首先作为子选择应用,然后在其上应用其他条件,如下所示:
SELECT DISTINCT this_.person_id AS y0_
FROM (
SELECT *
FROM coded_entity this_
WHERE this_.person_id IN (SELECT person_id
FROM person that
WHERE that.date_voided IS NULL
AND that.ssn = ?
AND that.tenant_id = ? )
) sub
where this_.code = ?
AND this_.tenant_id = ?
或者你可以用连接格式重写它:
SELECT DISTINCT this_.person_id AS y0_
FROM coded_entity this_
JOIN person that
ON that.person_id = this_person_id
AND that.date_voided IS NULL
AND that.ssn = ?
AND that.tenant_id = ?
WHERE this_.code = ?
AND this_.tenant_id = ?
或者我认为肯定会有效的是只要在两个表上正确收集统计数据,然后CBO就会正确决定。