我有问题。我的数据库是Oracle 9.这是我的SQL:
SELECT COUNT(distinct A.person_id)
INTO p_record_count
FROM A,
B,
F,
T
WHERE B.position_id = F.position_id **--Normal bussiness association**
AND T.field2 = A.org_id **--Normal bussiness association**
AND F.Organization_Id = A.org_id **--Normal bussiness association**
AND A.person_id = F.person_id **--Normal bussiness association**
AND F.primary_flag = 'Y' **--Normal bussiness association**
and sysdate between F.effective_start_date and
F.effective_end_date **--Normal bussiness association**
AND NOT EXISTS --very slow
(SELECT log.person_id
FROM cper.ehr_access_log log
WHERE log.person_id = A.person_id
AND log.access_page = 'login.do'
AND trunc(log.access_time) BETWEEN
to_date(p_startDate, 'yyyy-mm-dd') AND
to_date(p_endDate, 'yyyy-mm-dd'))
AND A.enable_flag = 'Y'; **--Normal bussiness association**
要求:获取未登录的人。
逻辑:得到我能得到的所有人,然后减去登录的人。
我只有一张包含登录记录的表。
表cper.ehr_access_log的记录超过10M。这是一张日志表。这个SQL大约需要30秒。
谢谢〜!我会试试。祝周末愉快〜:)
答案 0 :(得分:3)
表cper.ehr_access_log有超过10M条记录。它是一个日志 table.This大约需要30秒。可能在5秒内?
我想说如果不添加一些索引就不可能。但您可能想尝试以下建议
使用查询计划来识别热点。这可能是ehr_access_log
所需的表格,您可以使用该参数来说服其他人您需要索引。
尝试使用外部联接替换子查询,正如其他人建议的那样
您已加入B
和T
,但不加上谓词。你真的在查询中需要它们吗?
您可以通过避免trunc
来电来节省一些时间(不确定)。作为替代方案,请修改p_startDate
一天开始,p_endDate
到一天结束
答案 1 :(得分:2)
查询的“不存在”部分称为相关子查询。如果重写为OUTER连接,通常可以获得更好的性能。
模式是
select a from b where not exists (select 1 from c where b.a = c.a)
变为
select a from b left outer join c on b.a = c.a where c.a is null
答案 2 :(得分:1)
为了获得更好的效果,您必须 INDEX 表 cper.ehr_access_log
由于它是一个LOG表,因此请根据 person_id
制定每月计划以索引此表。这将减少一些查询时间。
答案 3 :(得分:1)
我认为您可以通过仅选择DISTINCT log.person_id记录来优化查询,它将减少日志中的记录数量。
您也可以尝试从第一部分开始排除:
SELECT COUNT(distinct A.person_id)
INTO p_record_count
FROM A,
B,
F,
T
LEFT OUTER JOIN cper.ehr_access_log log
ON log.person_id = A.person_id
AND log.access_page = 'login.do'
AND trunc(log.access_time) BETWEEN
to_date(p_startDate, 'yyyy-mm-dd') AND
to_date(p_endDate, 'yyyy-mm-dd')
WHERE B.position_id = F.position_id **--Normal bussiness association**
AND T.field2 = A.org_id **--Normal bussiness association**
AND F.Organization_Id = A.org_id **--Normal bussiness association**
AND A.person_id = F.person_id **--Normal bussiness association**
AND F.primary_flag = 'Y' **--Normal bussiness association**
and sysdate between F.effective_start_date and
F.effective_end_date **--Normal bussiness association**
AND log.person_id IS null
AND A.enable_flag = 'Y'; **--Normal bussiness association**