Postgres使用btree索引与MySQL B +树

时间:2015-10-08 07:21:48

标签: mysql performance postgresql b-tree b-tree-index

我们正在从MySQL迁移到PGSQL,我们有一个1亿行表。

当我试图确定两个系统使用多少空间时,我发现表的差异要小得多,但发现索引存在巨大差异。

MySQL索引占用的内容比表数据本身更大,而postgres使用的是相当小的大小。

  • 在挖掘原因时,我发现MySQL使用B +树来存储索引和postgres uses B树。

  • MySQL对索引的使用略有不同,它将数据与索引一起存储(由于增加的大小),但postgres没有。

现在问题:

  • 比较数据库上的B树和B +树,最好使用B +树,因为它们更适合范围查询O(m)+ O(logN) - 其中m在范围内并且查找是B +树中的对数?

    现在在B树中,对于范围查询,查找是对数的,因为它没有数据节点的链接列表底层结构,所以它会发射到O(N)。话虽如此,为什么postgres使用B树?它是否适用于范围查询(确实如此,但它如何在内部处理B树)?

  • 上述问题来自postgres的观点,但从MySQL的角度来看,为什么它比postgres使用更多的存储空间,在现实中使用B +树的性能优势是什么?

    < / LI>

我本可以错过/误解很多事情,所以请随时纠正我的理解。

编辑以回答Rick James的问题

  • 我正在使用InnoDB引擎for MySQL
  • 我在填充数据后构建了索引 - 就像我在postgres中所做的那样
  • 索引不是UNIQUE索引,只是普通索引
  • 没有随机插入,我在postgres和MySQL中都使用了csv加载,只有在此之后我创建了索引。
  • 索引和数据的Postgres块大小是8KB,我不确定MySQL,但我没有更改它,所以它必须是默认值。
  • 我不会把行称为大,他们有大约4个文本字段,长度为200个字符,4个十进制字段和2个bigint字段 - 19个数字长。
  • P.K是一个包含19个数字的bigint列,我不确定它是否笨重?在什么尺度上应区分笨重与非笨重?
  • MySQL表大小为600 MB,Postgres大约310 MB,包括索引 - 如果我的数学运算正确,这相当于大48%。但是有一种方法可以在MySQL中单独测量索引大小,不包括桌子大小?这可能会导致更好的数字。
  • 机器信息:我有足够的RAM - 256GB可以将所有表和索引放在一起,但我认为我们根本不需要遍历这条路线,我没有看到两者都有明显的性能差异。

其他问题

  • 当我们说碎片发生时?有没有办法去碎片化,以便我们可以说除此之外,没有什么可做的。顺便说一下,我正在使用Cent OS。
  • 有没有办法在MySQL中测量索引大小,忽略主键,因为我们可以实际看到哪种类型占用更多大小(如果有的话)。

3 个答案:

答案 0 :(得分:9)

首先,如果您不使用 InnoDB ,请关闭此问题,使用InnoDB重建,然后查看是否需要重新打开问题。 MyISAM 首选,不应讨论。

你是如何在MySQL中构建索引的?有几种方法可以显式或隐式地构建索引;它们会导致更好或更糟的包装。

MySQL:数据和索引存储在由 16KB 块组成的B +树中。

MySQL:UNIQUE索引(包括PRIMARY KEY必须在插入行时更新。因此,UNIQUE索引必然会有很多块拆分等。

MySQL: PRIMARY KEY与数据进行了群集,因此它实际上占用了零空间。如果以PK顺序加载数据,则块碎片很小。

可以动态构建非UNIQUE辅助密钥,这会导致一些碎片。或者可以在加载表之后构造它们;这导致更密集的包装。

辅助密钥(UNIQUE或不是)隐含地在其中包含PRIMARY KEY。如果PK是&#34;大&#34;那么二级钥匙很笨重。你的PK是什么?这是答案&#39;?

理论上,完全随机插入BTree导致块大约 69%已满。也许这就是答案。 MySQL是否大45%(1/69%)?

对于100M行,可能有许多操作受I / O限制,因为您没有足够的RAM来缓存所需的所有数据和/或索引块。如果所有内容都被缓存,那么B-Tree与B + Tree不会产生太大的影响。让我们分析当事情没有完全缓存时范围查询需要发生什么。

对于任一类型的树,操作都以树中的向下钻取开始。对于MySQL,100M行将具有大约4级深度的B +树。 3个非叶节点(同样是16KB块)将被缓存(如果它们已经不存在)并被重用。即使对于Postgres,也可能发生这种缓存。 (我不知道Postgres。)然后范围扫描开始。使用MySQL,它会遍历块的其余部分。 (经验法则:块中有100行。)同样适用于Postgres?

在块结束时,必须发生一些不同的事情。对于MySQL,有一个指向下一个块的链接。从磁盘(如果没有缓存)获取该块(包含100多行)。对于B树,需要再次遍历非叶节点。 2,大概还有3个级别仍然被缓存。我预计需要从磁盘仅1 / 10K行获取另一个非叶子节点。 (10K = 100 * 100)也就是说,Postgres可能比MySQL更频繁地击中磁盘1%,即使是在&#34;冷却#34;系统

另一方面,如果行是如此胖,只有1或2可以适合16K块,&#34; 100&#34;我继续使用更像是&#34; 2&#34;,1%可能变成50%。也就是说,如果你有大行,这可能是&#34;答案&#34; 。是吗?

Postgres中的块大小是多少?请注意,上面的许多计算都取决于块和数据之间的相对大小。这可能是一个答案吗?

结论:我已经给出了4个可能的答案。您是否想要增加问题以确认或反驳每个适用的问题? (二级索引的存在,大型PK,二级索引的低效构建,大行,块大小......)

关于PRIMARY KEY的补遗

对于InnoDB,需要注意的另一件事是:在加载数据之前,最好在表的定义中使用PRIMARY KEY。最好在LOAD DATA之前按PK顺序对数据进行排序。在没有指定任何PRIMARY KEYUNIQUE密钥的情况下,InnoDB构建了一个隐藏的6字节PK;这通常是次优的。

答案 1 :(得分:2)

MySQL和PostgreSQL在这里并不具有可比性Innodb使用索引来存储表数据(而二级索引只是指向pkey)。这对于单行pkey查找和B +树非常有用,可以在pkey字段上使用范围查询,但是对于其他所有内容都有性能缺陷。

PostgreSQL使用堆表并将索引放在一起。它支持许多不同的索引算法。根据您的范围查询,btree索引可能对您没有帮助,您可能需要GiST索引。类似地,GIN索引适用于成员查找(对于数组,fts等)。

我认为使用btree是因为它擅长于简单的用例:什么roes包含以下数据?例如,这成为GIN的构建块。

但PostgreSQL不能使用B +树是不正确的。 GiST以通用格式构建在B + Tree索引上。因此,PostgreSQL为您提供了使用B +树的选项,它们派上用场。

答案 2 :(得分:1)

在数据库中,您经常会查询谁提供一些数据范围,如id为100到200 在这种情况下

  • B-Tree需要遵循从根到叶子的路径,以获取每个条目以获取数据指针。
  • B + -Trees可以“走过”叶子,并且必须在第一次(即id为100)时遵循叶子的路径

这是因为 B + -Tree 仅存储叶子中的数据(或数据指针),并且叶子是链接的,因此您可以执行快速的有序遍历。

<强> B + - 树 B+-Tree

另一点是:
在B + Trees中,内部节点仅存储指向其他节点的指针而没有任何数据指针,因此您有更多的空间用于指针,并且您需要更少的IO操作,并且您可以在内存页面存储更多节点指针。

因此对于范围查询B + -Trees是最佳数据结构。对于单个选择,B-Trees可能更好(树的深度/大小的原因),因为数据指针也位于树内。