以下是域
的简化模型简而言之,单位向客户授予文件。有两种类型的单位:主要单位和他们的子单位。两者都属于同一个省,一个省可能属于多个城市。文档有许多事件(处理历史)。客户属于一个城市和省份。
我必须编写查询,在给定目标主单元代码的情况下返回随机文档集。以下是标准:
但是...
可能有数百万行,查询必须尽可能快,经常执行。
我不确定如何以理智的方式构建这种复杂的查询。我正在使用 Oracle 和 PL / SQL 。这是我尝试过的东西,但它没有按预期工作(返回错误的数据)。我应该如何重构此查询并获得随机结果,还要遵守所有这些边界规则?我也担心关于联合和表现的表现。
CURSOR c_documents IS
WITH documents_cte AS
SELECT d.document_id AS document_id, d.create_dt AS create_dt,
c.customer_id
FROM documents d
JOIN customers c ON (c.customer_id = d.customer_id AND
c.province_id = (SELECT region_id FROM unit WHERE unit_code = 1234))
WHERE exists (
SELECT 1
FROM event
where document_id = d.document_id AND
event_code = 10
AND create_dt =
SELECT MAX(create_dt)
FROM event
WHERE document_id = d.document_id)
SELECT * FROM documents_cte d
WHERE create_dt = (SELECT MAX(create_dt)
from documents_cte
WHERE customer_id = d.customer_id)
如何以高效,随意的方式正确地进行此查询?我不是要求确切的解决方案,而是至少要求指导。
答案 0 :(得分:0)
尽可能避免使用层次表。在你的情况下,你使用一个分层表来允许无限的深度,但最后它只是你存储的两个级别:省和他们的城市。最好只有两个表:一个用于省,一个用于城市。这不是什么大问题,但这会使您的数据模型更简单,更容易查询。
下面我开始使用WITH
子句来获取城市表,因此不存在。然后我一步一步走:获得属于该单位的客户,然后获取他们的文件并对他们进行排名。最后,我选择排名的文档,并随机选取10个排名最高的文档。
with cities as
(
select
c.region_id as city_id,
o.region_id as province_id
from region c
join region p on p.region_id = c.parent_region_id
)
, unit_customers as
(
select customer_id
from customer
where city_id in
(
select city_id
from cities
where
(
select region_id
from unit
where unit_code = 1234
) in (city_id, province_id)
)
)
, ranked_documents as
(
select
document.*,
row_number(partition by customer_id order by create_dt desc) as rn
from document
where customer_id in -- customers belonging to the unit
(
select customer_id
from unit_customers
)
and document_id in -- documents with latest event code = 10
(
select document_id
from event
group by document_id
having max(event_code) keep (dense_rank last order by create_dt) = 10
)
)
select *
from ranked_documents
order by rn, dbms_random.value
fetch first 10 rows only;
这并不考虑获取两种文档类型,因为这与每个客户获取最新文档的规则相矛盾。
从Oracle 12c开始, FETCH FIRST
可用。在早期版本中,您将使用另一个子查询,而使用另一个ROW_NUMBER
。
至于速度,我建议查询这些索引:
create index idx_r1 on region(region_id); -- already exists for region_id = primary key
create index idx_r2 on region(parent_region_id, region_id);
create index idx_u1 on unit(unit_code, region_id);
create index idx_c1 on customer(city_id, customer_id);
create index idx_e1 on event(document_id, create_dt, event_code);
create index idx_d1 on document(document_id, customer_id, create_dt);
create index idx_d2 on document(customer_id, document_id, create_dt);
最后两个中的一个将被使用,另一个不会。检查EXPLAIN PLAN
,然后删除未使用的。