故意破坏 PostgreSQL 中的索引

Vip*_*kla 2 postgresql index testing index-tuning

我需要知道是否有任何方法可以故意破坏 PostgreSQL 中的索引。

我找了很久,但从未见过有人提到过这样的行为。

Erw*_*ter 5

我认为@Craig 的评论更重要,它解决了你问题背后的意图。无论如何,回答所提出的问题

一种简单的方法(以及许多其他方法)是伪造一个IMMUTABLE函数并基于它建立一个索引,就像昨天的这个答案中概述的那样:

CREATE OR REPLACE FUNCTION f_fake_immutable_ts()
  RETURNS timestamp LANGUAGE sql COST 1 IMMUTABLE AS
$$SELECT timestamp '2015-07-25 01:00'$$;
Run Code Online (Sandbox Code Playgroud)

基于它创建部分索引:

CREATE INDEX tbl_created_at_idx ON tbl (tbl_id)
WHERE  created_at > f_fake_immutable_ts();
Run Code Online (Sandbox Code Playgroud)

索引依赖于函数始终为相同的输入返回相同的输出。更改函数(以返回不同的时间戳)会导致索引损坏。

除了测试每个条目之外,无法识别该索引是否已损坏。


Cra*_*ger 5

Erwin 描述了一种创建索引的方法,该方法违反了 PostgreSQL 关于索引的假设,产生的结果可能不正确且与基础表不匹配。

这是腐败的一种。

另一种损坏是索引中的块完全无效 - 清零、替换为随机值等。读取此类索引很可能会导致 if ERROR/when 该块被访问。dd您可以通过从/dev/zero/dev/urandom到索引中的某个偏移量来创建这样的索引。

另一种损坏是简单的位翻转。在这里,您可以从索引关系中选择一个随机(或目标)字节,并将其从 0 更改为 1,反之亦然。如果内存错误(包括伽马辐射、热问题等)导致索引页在刷新到磁盘之前在内存中被损坏,那么在现实中就会发生这种情况。用 C、Python 或其他语言编写程序来执行此操作很简单。

另一种损坏是索引在结构上有效但已经过时。它不反映当前表内容,因为由于某种原因,未写入索引的某些更新。indisvalid您可以通过设置为false,对索引关系执行一些插入/更新/删除,然后再次设置来创建这种情况indisvalid = true。由于 PostgreSQL 会忽略带有 的索引indisvalid = f,假设它正在构建过程中,它不会更新它,因此您将拥有过时的索引内容。

另一种损坏涉及 B 树结构问题,例如缺少叶子、循环引用等。造成此类损坏的最佳方法是修改 PostgreSQL 的源代码,使其故意执行这些操作。仅使用索引关系来完成它们是很困难的。

另一种索引损坏是截断。索引看起来不错,但结尾缺失。

存在索引关系完全丢失的情况。目录条目存在,但支持文件不存在。

索引关系可以存在,但充满随机垃圾。

这样的例子还在继续。几乎根据定义,腐败可以是任何不正常的事情。

这就是“模糊测试”如此有趣的原因之一。因为程序员非常非常难以预测每种可能的状态并防范每种可能的问题,因此通常可以通过进行随机更改并查看哪些问题来发现问题。