【问题标题】:What is the fastest way to select count of entries in big SQL table?在大 SQL 表中选择条目数的最快方法是什么?
【发布时间】:2014-03-02 22:39:34
【问题描述】:

我有一张有 2 亿行的表。
让我们调用表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的解决方案?

【问题讨论】:

    标签: sql database oracle plsql


    【解决方案1】:

    一般来说,“基于集合”的方法(使用查询)会比使用 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;
    

    【讨论】:

    • 全名作为key仅用于示例。但感谢您的评论。如果我不过滤它们,我有大约 100 万个不同的“employee_fullname”,它不会填满我机器的内存吗?我会尽快尝试您的解决方案,并让您知道它是否确实加快了我的查询速度。感谢您的帮助。
    • 我花了 6.3 秒才得到 10 行。用我的 pl/sql 块。与之前的 2000 秒相比有了巨大的改进。就像你告诉我的那样修复我的索引。
    • @Roy 。 . .这非常好,提高了 99.7%。如果这适用于所有数据,那么 PL/SQL 代码将在几个小时内完成。性能的关键是索引是否适合内存。虽然,即使没有,您可能仍在谈论数小时而不是数天。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-24
    • 1970-01-01
    • 1970-01-01
    • 2017-10-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    相关资源
    最近更新 更多