如何最好地索引这个table?

How to best index this table?

我在 PostgreSQL 中有一个很大的 table(>2000 M 行),必须尽快查询。它代表生物样品中基因表达的测量。问题是有时测量直接在基因上("probe" 然后是 NULL),有时测量是通过基因的 "probes" 完成的("gene" 然后仍然设置)。一个基因可以有多个探针。没有其他 table 包含基因-探针关系。

CREATE TABLE "gene_measurements" (
  "gene" INTEGER NOT NULL REFERENCES "genes" ON DELETE CASCADE,
  "sample" INTEGER NOT NULL REFERENCES "samples" ON DELETE CASCADE,
  "probe" INTEGER REFERENCES "probes" ON DELETE CASCADE,
  "value" REAL NOT NULL
);

常见查询包括获取给定样本中所有基因的表达,获取给定gene/probe在所有样本中的表达,或获取给定样本中给定gene/probe的表达.

现在我有以下覆盖索引。它工作正常,但非常 space 消耗。

CREATE INDEX "gene_measurements_gene_sample_value_index" ON "gene_measurements" ("gene", "sample", "value");
CREATE INDEX "gene_measurements_sample_gene_value_index" ON "gene_measurements" ("sample", "gene", "value");
CREATE INDEX "gene_measurements_sample_probe_value_index" ON "gene_measurements" ("sample", "probe", "value");
CREATE INDEX "gene_measurements_probe_sample_value_index" ON "gene_measurements" ("probe", "sample", "value");

我可以做些什么聪明的事情来获得更整洁的 and/or 更小的实现,同时保持速度?谢谢!

您可以在space和时间之间选择一个任意阈值。现在,您已经将整个 table 索引了四次。这显然消耗了很多space.

您可以从索引中删除一些数据以换取更快的运行时间:

  • 例如,您可以从所有索引中删除 value。但是,除了在索引中查找之外,还需要查找数据。
  • 您也可以完全删除一些索引。例如,根据您的数据,您可以删除 (sample, gene)(sample, probe)。这会删除一个完整的数据覆盖范围,同时仍然允许您使用 sample 部分来查询条件 sample 和删除的列。同样,您删除的案例没有以前那么快。

如果您的目标是不惜一切代价实现最短运行时间,那么所有这些建议都不适合您。我认为目前 PostgreSQL 世界中没有任何东西可以解决您的问题。

由于您的数据简单,用例有限,您可以考虑PostgreSQL以外的解决方案。特别是,您基本上只需要一个 B-Tree 数据结构。 (或多个。)有 other solutions to build such a data structure, e.g., QDBM。尽管如此,您仍需要构建多个这样的结构来针对每个 select 类型进行优化。 space 中可实现的节省我认为不是很高——基本上,您可以摆脱数据,但摆脱索引 none。因此,您可以大致节省当前存储大小的 1/5,但代价是软件生态系统中的功能受限和复杂性增加。

你必须决定你需要什么,你想要什么,你想为这些目标牺牲什么。考虑到我在这里写下的内容,我会坚持使用 PostgreSQL。

SQL-table确实需要一个主键。从理论上讲,没有密钥的 table 是没有意义的。 (实际上,table 3G 行缺少 PK 是一场灾难)

在您的例子中,自然键 似乎是 (gene_id,sample_id,probe_id) 列的组合。需要这三列的值才能 唯一地解决 value.

问题是你的if probe is absent; measurement was directly on the gene反约束。 这将禁止三列键。 删除此异常将允许多列主键。 现在,数据技巧是插入一个 虚拟行 到探测器中,例如,id=0.

INSERT INTO probe(probe_id, probe_when, probe_name)
 VALUES( 0, '1901-01-01 00:00:00', 'Dummy probe');

现在更新 gene_measurements 将 probe IS NULL 更改为 probe=0


CREATE TABLE gene_measurements (
  gene INTEGER NOT NULL REFERENCES genes(gene_id) ON DELETE CASCADE
  , sample INTEGER NOT NULL REFERENCES samples(sample_id) ON DELETE CASCADE
  , probe INTEGER NOT NULL REFERENCES probes (probe_id)
  , value REAL NOT NULL
        , PRIMARY KEY ( gene_id, sample_id,probe_id)
);

也许也可以添加一些其他索引,以不同的顺序来帮助特定的查询,例如:

CREATE UNIQUE INDEX ON gene_measurements (sample_id,gene_id,probe_id);

并且您需要一个用于探针 FK 的支持索引,任何以探针作为其第一列的索引都可以:

CREATE INDEX ON gene_measurements (probe_id, ...);