我有一张200米行的桌子
让我们调用表格employee_internet_history
行:employee_fullname || website || date || more data
。
该表在employee_fullname
列上有一个索引。
我还有另一张桌子eu_employees
有100行;每一行:employee_fullname || more data
。
我想创建一个查询,以选择每位员工浏览的前3个网站。
我正在使用Oracle Database
所以我考虑使用PL/SQL
来实现这一目标。
目前我正在使用
declare
cursor top100workers is
select * from eu_employees
where rownum < 100;
begin
for worker in top100workers
LOOP
DBMS_OUTPUT.PUT_LINE(worker.employee_fullname ||' top 3 webpages:');
for TOP3 in (
SELECT /*+ parallel*/ website,
COUNT(website) AS num
from employee_internet_history
WHERE employee_internet_history.employee_fullname = worker.employee_fullname
group by website
order by num desc
)
LOOP
DBMS_OUTPUT.PUT_LINE('website = ' || TOP3.website || ' ,times surferd: '||top3.num);
end loop;
end LOOP;
end;
/
对于每个员工,此查询大约需要200秒。 我真正的eu_employee表有超过8000条记录 这意味着用我的方式计算这个时间需要19天。
1)我怎样才能加快速度?
2)为什么需要花费这么长时间? 如果员工的所有记录都被编入索引,则应该使用O(1)来查找它们并计算它们。
此外,查询不依赖于彼此, 3)我可以并行运行几个查询吗?
4)我看到有几个提示可以在并行模式下运行,哪一个最适合我的需要?
5)有没有使用pl/sql
的解决方案?
答案 0 :(得分:4)
通常,“基于集合”的方法(使用查询)比使用PL / SQL更快。
以下查询可以执行您想要的操作:
select eih.*
from (select employee_id, website, count(*) as cnt,
row_number() over (partition by employee_id order by count(*) desc) as seqnum
from employee_internet_history eih
group by employee_id, website
) eih
where seqnum <= 3;
我不确定您是否可以让它运行得更快,因为您必须首先在员工/网站级别汇总数据。如果您想了解更多员工信息,请加入eu_employees
。
顺便说一下,使用employee_fullname
作为连接键是一个非常糟糕的主意。人们可能会因为各种原因改变他们的名字。
我还要补充一点,使用employee_internet_history(employee_fullname, website)
上的索引可能会使查询运行得更快。您也可以将join
遗漏给员工信息。问题中至少没有任何内容表明需要它(除非它用于过滤)。
编辑:
性能高度依赖于您的硬件和内存。您可以通过以下方式使用员工子集来加速查询:
select eih.*
from (select employee_id, website, count(*) as cnt,
row_number() over (partition by employee_id order by count(*) desc) as seqnum
from employee_internet_history eih join
(select ee.*
from eu_employees ee
where rownum < 100
) ee
on eih.employee_id = w.employee_id
group by employee_id, website
) eih
where seqnum <= 3;