VB_*_*VB_ 6 mysql rdbms postgresql performance query-performance postgresql-performance
我已经阅读了相同架构/查询的 MySQL 和 PostgreSQL 之间的性能差异。以下是对文章的简要复述:
PostgreSQL 表是堆表(意味着没有聚集索引)......(Postgres)表的主键查找需要点击索引,查找文件中的位置,然后点击堆表并拉出记录。这意味着随机磁盘 I/O 的数量... InnoDB 使用不同的方法。使用 InnoDB,表是一个 b 树索引(聚集,物理排序)...... PK 查找所需的随机磁盘 I/O 更少......同时,索引扫描需要遍历两个索引而不是一个(index -> PK index -> table row ),这意味着使用主键以外的任何索引最终都会变慢,而顺序扫描仍然更慢。
哪种查询使用 Postgres 比使用 MySQL InnoDB 快得多?
我理解为什么 PK 查找对于 MySQL 来说要好得多。我不明白:
PS Internet 说 Postgres 更适合复杂查询和子查询,但我仍然不明白为什么它更好?
Mat*_*sOl 18
为了避免激烈的战争,我只会看一眼每个存储在查询时的工作方式,而不是真正的基准测试。我将使用此表作为参考(应稍微修改代码以在两个 RDBMS 上运行):
CREATE TABLE employees (
emp_id int,
name varchar,
depto_no int,
salary decimal,
CONSTRAINT emp_pk PRIMARY KEY (emp_id);
);
CREATE INDEX emp_depto_idx ON employees (depto_no);
Run Code Online (Sandbox Code Playgroud)
在 PostgreSQL 上将有 3 个结构:
employees
堆,这基本上是顺序存储在表(就像你想象一个表)emp_pk
索引(其也是主键),存储为B树索引,其中每个元件具有一个指针到employee
/在磁盘偏移的堆,与所述准确的页emp_depto_idx
索引,也就是像emp_pk
,B树的指针到堆,不同之处在于它不强制唯一性在 MySQL InnoDB 上,只有两个:
emp_pk
并将employees
存储为一个结构,即按emp_id
列排序的 B 树,并将其他列上的值作为有效负载保留在叶节点中。emp_depto_idx
index 是一个 B 树,它在每个元素上都有emp_id
引用该行的值(不是物理位置指针)。为什么 PK 查找对 MySQL 更好
我知道你知道这一点,但让我们说清楚。
当您像这样查询时:
SELECT * FROM employees WHERE emp_id = 10;
Run Code Online (Sandbox Code Playgroud)
在 PostgreSQL 上,它可以浏览emp_pk
索引(对 B 树索引进行一次扫描),然后获取页面/偏移量以从employees
堆表中获取引用行(一次直接页面/行获取,而不是真正的扫描)。因此,对索引进行一次扫描,对堆进行一次直接获取。
在 MySQL 上,它只会浏览主键索引(对 B 树索引进行一次扫描),因为所有信息都已经存在,不需要其他查找。因此,只需对 index 进行一次扫描。
所以,虽然 PostgreSQL 需要做一次扫描和一次获取,但 MySQL 只做一次扫描。
为什么通过两个索引(InnoDB,通过非 PK 索引查找)查找要慢得多?它是否需要两倍以上的 I/O 或 CPU?它可以弥补 PK 查找提升的巨大好处吗?
现在,假设另一个查询:
SELECT * FROM employees WHERE depto_no = 14;
Run Code Online (Sandbox Code Playgroud)
在 PostgreSQL 上,它与其他的没有太大区别。它将扫描emp_depto_idx
,然后对于返回的每一行,直接从堆中获取值。因此,对索引进行一次扫描,并在堆上为匹配的每一行直接获取。
在 MySQL 上,它将扫描emp_depto_idx
(对索引进行一次扫描),然后,对于返回的每一行,它将获取引用emp_id
并扫描主键索引。因此,对二级索引进行一次扫描,对匹配的每一行的主索引进行一次扫描。
看到不同?PostgreSQL 会先进行一次扫描,然后使用直接指针获取每个匹配的行,而 InnoDB 会先进行类似的扫描,然后对每个匹配的行进行另一次扫描。现在,如果部门 14 的员工很少,它可能足够快,但是随着员工的增加,它会变得很慢(当然,它在两个 RDBMS 上都会变慢,但InnoDB的曲线可能更高)。
为什么 InnoDB 顺序扫描更慢?
简单的答案,因为它不是真正的“顺序”......
好吧,让我们看看最简单(当然也很慢)的查询:
SELECT * FROM employees;
Run Code Online (Sandbox Code Playgroud)
在 PostgreSQL 上,它可以简单employees
地按物理顺序逐行扫描整个堆(不管这里的插入顺序如何,重要的是现在元组和页面的物理排列方式)。
在 InnoDB 上,它需要遍历索引,这意味着更多的随机扫描(因为索引页的物理和逻辑顺序不一定相同)。
如果您考虑磁盘,则差异非常明显,众所周知,顺序访问比随机访问快得多。对于 SSD 来说,这不一定是真的,尽管在顺序访问方面仍然有优势,比如预读。所以在大多数情况下,PostgreSQL 的完整扫描可能比 InnoDB 更快,至少对于相当大的表(注意我没有定义什么是“大”,你必须尝试一下,看看差异真正重要的地方,它可能只是在许多情况下很重要)。对于两个 RDBMS,最好的方法是设计您的模型和查询以避免完全扫描(如果可能)。
Internet 说 Postgres 更适合复杂查询和子查询,但我仍然不明白为什么它更好?
这是一个很大的话题,可能会引发更多的火焰战争,所以我只给你一些例子。通常说 PostgreSQL 更适合复杂查询,如果您简单地考虑一下 MySQL 中不存在的查询功能(尚未考虑性能),这可能是正确的,例如:
除此之外,这两者的计划者和执行者有很多不同。例如,PostgreSQL 可以使用嵌套循环、哈希联接和合并联接进行联接,而 MySQL 只能使用嵌套循环进行联接。尽管如此,MySQL 在它的嵌套循环算法中有很多优化,而 PostgreSQL 在它的规划器上有一个更难的选择,有时它会出错(但 MySQL 也是如此)。
这个答案只是对该主题的快速浏览,当涉及到性能时,这两个 RDBMS 仍有很多事情需要考虑,例如仅索引扫描、真空与撤消、并行性等。事实是你可以'简单地说,一个比另一个快,我很清楚(对你来说是这样吗?)一个在某些环境中可能更快,而另一个在其他环境中可能更快。