【问题标题】:Postgres vs oracle doing 1 million sqrts am I doing it wrong?Postgres vs oracle 做 100 万次 sqrts 我做错了吗?
【发布时间】:2014-09-27 09:27:07
【问题描述】:

我们正在尝试了解 Oracle 与 PostgreSQL 的原始性能。我们有丰富的 oracle 经验,但对 PostgreSQL 不熟悉。我们将使用我们的数据等运行大量查询。但首先我们想看看它们在基本内核任务上的执行情况,即数学和分支,因为 SQL 是建立在此之上的。

在 AWS RDS 中,我们创建了两个 db.m3.2xlarge 实例,一个包含 oracle 11.2.0.4.v1 许可证,另一个包含 PostgreSQL (9.3.3)

在这两种情况下,我们运行的代码都计算了 100 万平方根(从 1 到 1 磨)。 Then 做了同样的事情,但在 If..Then 语句中。

结果有点令人不安:

Oracle      4.8 seconds

PostgreSQL  21.803 seconds

添加 if 语句:

Oracle      4.78 seconds

PostgreSQL  24.4 seconds

代码 甲骨文平方根

SET SERVEROUTPUT ON
SET TIMING ON

DECLARE
  n NUMBER := 0;
BEGIN
  FOR f IN 1..10000000
LOOP
    n := SQRT (f);
  END LOOP;
END;

PostgreSQL

DO LANGUAGE plpgsql $$ DECLARE n real;
BEGIN
FOR f IN 1..10000000 LOOP
n = SQRT (f);
END LOOP;
RAISE NOTICE 'Result => %',n;
END $$;

oracle 添加 if

SET SERVEROUTPUT ON
SET TIMING ON

DECLARE
  n NUMBER := 0;
BEGIN
  FOR f IN 1..10000000
LOOP
  if 0 =0 then
    n := SQRT (f);
    end if;
  END LOOP;

postgres 添加 if

DO LANGUAGE plpgsql $$ DECLARE n real;
BEGIN
FOR f IN 1..10000000 LOOP
if 0=0 then 
n = SQRT (f);
end if;
END LOOP;
RAISE NOTICE 'Result => %',n;
END $$;

我为 PostgreSQL 使用了一个匿名块。我也把它作为一个函数来做,得到了相同的结果

CREATE OR REPLACE FUNCTION testpostgrescpu()
  RETURNS real AS
$BODY$
declare
     n real;
BEGIN
   FOR f IN 1..10000000 LOOP        
    n = SQRT (f);       
   END LOOP;        


   RETURN n;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION testpostgrescpu()
  OWNER TO xxx

根据我们对 PostgreSQL 的了解以及它在许多方面与 Oracle 的可比性,我们对结果感到吃惊。我们对 PostgreSQL 的编码是否错误?我们缺少什么,或者它是这样的。

注意:一旦我们开始在 Oracle 和 PostgreSQL 中对完全相同的数据运行查询,我们就会看到类似的模式。在基本查询方面差别不大,但随着它们开始变得越来越复杂,Oracle 的速度提高了大约 3-5 倍。

同样,这是在相同的 AWS RDS 实例上运行的,我们在一天中的不同日子多次运行它们,结果始终相同

【问题讨论】:

  • Oracle实例有可能是多线程的吗?我真的想知道默认系统参数是否对 Oracle 实例更有效(这可能不会影响循环,但会影响其他操作)。
  • 它不像PostgreSQL那样多线程它的多进程Oracle可以运行多线程但很少这样使用

标签: sql database oracle postgresql amazon-web-services


【解决方案1】:

正如其他人所说,您的示例测试毫无意义。

我认为您遇到的基本问题是您对 PostgreSQL 一无所知,并且正在尝试与 Oracle 相同的基本技巧。

我们正在尝试了解 Oracle 与 PostgreSQL 的原始性能

那真的意味着有什么用吗?除非您尝试测量原始磁盘读取或类似情况。

我们已经尽可能地调整它们(检查所有参数更改了随机页面成本,将 seq 扫描设置为关闭等)

嗯,将 seq_scan 设置为 off 不太可能是您想要做的事情,除了在探索测试用例时强制规划器。是什么让你这样做?它在手册中的哪个位置提出了建议?你没有说如何你改变了 random-page-cost 也没有说你如何确定你有正确的价值。

我们发现,对于 PostgreSQL,如果表大于共享内存设置的 25%,则其表数据不会被缓存。

嗯,这显然是不可能的。缓存发生在 PostgreSQL 和操作系统级别,磁盘块被缓存。你如何衡量这个?

(在我们的例子中,AWS 30 gig 实例有一个 7 gigs 的共享内存,一旦我们获得低于 2gigs 的表大小,它就会再次开始缓存)

那么,您如何调整 shared_mem 的大小?我试图想象一个场景,其中 2G 和 7G 都是合理的值,但我遇到了麻烦。您不提供任何内存使用信息,因此没有人知道发生了什么。

我认为你需要做的是:

  1. 喝杯热茶/咖啡。
  2. 通读manuals
  3. 查看 wiki,例如Tuning Your PostgreSQL Server
  4. 一旦您对 work-mem 和 shared-mem 的操作方式有了合理的把握,就可以在服务器上进行一些测量,以便查看内存使用情况、磁盘 I/O 等。
  5. 确保您有一个basic understanding 以了解如何EXPLAIN ANALYZE 您的查询。
  6. 订阅 postgresql.org 邮件列表之一(性能似乎合理),这样您就有了可以进行讨论的地方。
  7. 然后开始考虑衡量绩效。

种情况下,Oracle 会比 PostgreSQL 更智能,但普遍的全面大幅放缓并不是您所期望的。

【讨论】:

    【解决方案2】:

    这是一个猜测。我预计 Oracle 在此类计算上会比 Postgres 慢。但是,我认为您的documentation 可能存在性能问题:

    numeric 类型可以存储位数非常多的数字 并准确执行计算。特别推荐用于 存储货币金额和其他数量的准确性 必需的。但是,数值的算术比较慢 到整数类型,或到中描述的浮点类型 下一节。

    您的代码没有声明f 的数据类型。根据上下文,它将被分配为整数。但是,sqrt() 函数采用浮点或 numeric 常量。这些是不等价的(我猜当numeric 时,函数会更慢)。我的猜测是整数f 被转换为number 而不是real 进行操作。

    尝试通过将f 显式声明为real 或在函数调用之前强制转换来运行测试。这可能会提高性能。

    【讨论】:

    • 在同一时间实现了真实。还使 f 成为整数并且完全相同的时间 DO LANGUAGE plpgsql $$ DECLARE n real;声明真实; BEGIN FOR f IN 1..10000000 循环 n = SQRT (f);结束循环;提高通知 '结果 => %',n;结束 $$;
    • Gordon 请参阅下面我对 Hambone 的评论。 100 万次索引循环 oracle 速度提高 3-4 倍
    【解决方案3】:

    除非您碰巧在 pl/sql 或 pg pl/sql 中进行了大量计算,否则我看不出这将如何成为一个有用的指标。无论如何,这并不是真正推荐的,可以在 C 中本地完成,也可以通过调用 Java 类来完成。 Oracle 可以在某些平台/版本上将 pl/sql 本地编译为 c,因此这可能是您看到速度差异很大的原因之一。

    数据库的速度将更好地取决于它执行查询的能力,可能包括具有正确统计信息的联接或写入和更新数据。对于 Oracle 和 Postgres 等数据库,如果您有 OLTP 应用程序,那么在多用户和事务环境中执行此操作将是一个更好的测试。据我所知,Postgres 在与 Oracle 竞争方面做得很好,但这取决于您的应用程序。

    为了更好地描述和分析 Oracle,我建议查看 asktom https://asktom.oracle.com/ 论坛。我不确定 postgres 是否有类似的东西。

    【讨论】:

      【解决方案4】:

      说实话,你的基准完全没有意义。

      您正在计算 100 万平方根,然后立即丢弃结果;根据您的优化设置,我希望编译器完全摆脱您的循环。

      您应该至少将结果存储在某处或将它们用于其他计算(例如,通过计算总和)。

      另外,我不同意你的说法即数学和分支,因为 SQL 是建立在此之上的。 RDBMS 可以做很多事情,但有效地计算平方根肯定不是它的强项之一。如果您真的非常需要这种计算,将其移出数据库并为此使用某种专门的软件会更有意义,例如R

      【讨论】:

      • 你说得对,Oracle 优化器很可能排除了整个外观。 Oracle 的 PL/SQL(类似 ADA)在 p-code、m-code 两个级别上进行了优化,并进行了各种优化。例如,在某些情况下,即使您没有在源代码中使用它们,Oracle 也会使用批量操作。
      【解决方案5】:

      我对这些基准有点惊讶,但我倾向于在理论上同意 Frank Schmitt。虽然我不会说它“完全没有意义”,但如果您要比较两个 DBMS 系统,我认为您需要了解的不仅仅是每个系统如何进行数学运算。

      不管怎样,我几乎只在我的前任雇主处使用 Oracle。在我的新角色中,我们的主要 DBMS 是 Sybase ASE,它缺少我习惯使用的许多工具,而我们将 PostgreSQL 用作权宜之计。

      毫无疑问,有比我将要提供的更好的文章,但从新手的角度来看:

      我想念关于 Oracle 的事情:

      • 操作系统身份验证(允许用户根据他们的 Windows/Unix 凭据登录),没有混乱的密码问题
      • “合并”语句
      • 通过 OCI(ODP.net、DBD::Oracle)进行批量插入和更新
      • 通过过程部分提交的能力
      • 出色的 IDE 的可用性(如 All Around Automation PL/SQL Developer)
      • 位图索引
      • 更无缝的 DBlinks

      我喜欢 PostgreSQL 的地方:

      • 价格标签
      • “复制”比 SQL*Loader 好用得多
      • 适用于 .NET 的 ODBC 和 Npgsql.dll 等驱动程序的可用性
      • SQL 中的自定义函数不会降低查询性能
      • 能够使用 PL(即 Perl)以外的语言创建自定义函数
      • 更易于使用的数据类型,例如日期、时间、时间戳和间隔
      • 一种边界直观的更新语法(并且不需要额外的存在包装器)

      再说一次,我远非专家。使用这两个数据库平台都很愉快,并且可以处理这么多繁重的工作。

      -- 编辑--

      我应该补充一点,直到今天我还没有弄清楚如何在 Oracle 中做到这一点:

      select * from pg_views
      where definition like '%inventory.turns%'
      

      【讨论】:

      • 伙计们,你们没有抓住重点。我们不在乎我们在做什么 100 万次它会看到算法是如何实现的,代码的效率如何等等。所以现在我们做了以下事情。我们有一个有 5000000 行的表。我们创建了一个从 1 到 100 万的循环,它通过主键从表中选择同一行(从 tablea 中选择 key_id 到 n,其中 primary_id = 11684473;)。我们对同一行进行了 100 万次唯一索引扫描。所以我们有 1 次物理读取,然后是 999999 从缓存中读取。 oracle 27 秒 postgreSQL 96 秒 3-4 次指标再次出现。
      • 关于“复制”也比 SQL*Loader 更容易使用请记住,一个错误和整个负载要么全部加载要么不加载。 sqloader 允许错误文件的最大数量等 SQL 中的自定义函数不会拖累查询性能 oracle 允许您索引函数 能够以 PL 以外的语言创建自定义函数 oracle 可以在 C++ 或 JAVA 中执行 oracle 具有时间戳和间隔数据类型
      • 很难相信 Oracle 有那么“好”,但到目前为止您展示的示例都令人头疼。我很好奇 AWS 上的性能增量与本机服务器有何不同。您的 OWS 实例是什么操作系统?
      • 另外,我知道我跑题了,但是关于副本,我认为相反的情况可能是正确的。在截断/复制时,如果有任何失败,则表恢复到其原始状态。我认为在很多情况下,旧的、好的快照比部分(或不完整)的快照更可取。使用 Oracle,当您截断时,它就完成了。我不一定要买或卖,但我认为副本更易于使用,并且除了易用性之外也有其优点。
      • Hambone,我们正在使用生产环境中的查询进行全面测试,结果对 PostgreSQL 来说更加令人痛苦。我们的查询很复杂(25 个表连接和十几个过滤器),我们已经加载了大约 500 演出的数据。 PostgreSQL 做的最好的速度是 oracle 的 1/2,大多数慢 4-5 倍,有些慢 50-100 倍。我们已经尽可能地调整它们(检查所有参数更改了随机页面成本,将 seq 扫描设置为关闭等),但大多数运行速度仍然较慢。
      【解决方案6】:

      您没有执行任何 PostgreSQL 基准测试。

      你真正在做的是一个 pl/pgsqlbenchmark。

      您可以使用这些PostgreSQL language extensions 中的任何一个进行此测试,您可能会得到完全不同的结果。

      有一个 pl/pgsql 解释器可以执行你的代码。它默认与 PostgreSQL 一起安装。 欲了解更多信息:

      使用 pl/java 你会运行一个 JVM,pl/sh 一个 shell 运行。

      【讨论】:

      • 用 url 添加解释会更容易
      【解决方案7】:

      plpgsql 不是针对性能进行广泛优化的语言。

      我不知道我为什么要在数据库内的显式循环中计算 1000 万平方根,但如果我这样做了,我会使用 plperl 来完成。

      【讨论】:

        【解决方案8】:

        这里的问题在于类型转换。 PostgreSQL sqrt 函数定义为接受双精度(浮点)或数字。 因此,在您的代码中发生的情况是整数被转换为 float(很快)sqrt 的 float 版本,结果是类型从 float 转换为 real(很慢)。

        要了解我在说什么,请尝试比较这两个代码示例的运行时间:

        DO LANGUAGE plpgsql $$
        DECLARE n real;
        BEGIN
            FOR f IN 1..10000000 LOOP
                n = f::float;
            END LOOP;
            RAISE NOTICE 'Result => %',n;
        END $$;
        
        DO LANGUAGE plpgsql $$
        DECLARE n float;
        BEGIN
            FOR f IN 1..10000000 LOOP
                n = f::float;
            END LOOP;
            RAISE NOTICE 'Result => %',n;
        END $$;
        

        在我的机器上,第一个需要 16 秒,第二个只需要 3 秒。

        这个故事的寓意是您需要小心使用的数据类型。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-06-15
          • 1970-01-01
          • 1970-01-01
          • 2019-11-28
          • 2019-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多