我在PostgreSQL中有一个大表(>2000 M行),必须尽快查询。它代表了生物样本中基因表达的测量结果。事情是,有时测量是直接在基因上进行的("探针 "则为NULL),有时测量是通过一个基因的 "探针 "来完成的("基因 "则仍为设置)。一个基因可以有多个探针。没有其他表包含基因-探针的关系。
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
);
常见的查询包括获取给定样本中所有基因的表达,获取给定基因探针在所有样本中的表达,或者获取给定基因探针在给定样本中的表达。
现在的情况是,我有以下覆盖索引。它工作得很好,但非常耗费空间。
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");
有没有什么聪明的办法可以让我在保持速度的同时,得到一个更整洁、更小的实现?谢谢!我在PostgreSQL里有一个大表。
一个SQL表真的 需要 一个主键。理论上讲,一张表没有主键是没有意义的。(在实践中,一张表的3G行缺少PK是灾难)
在你的情况下, 天然键 似乎是结合了 (gene_id,sample_id,probe_id)
列。这三栏的数值需要用于 独树一帜 value
.
问题是你的 if probe is absent; measurement was directly on the gene
反约束.这将禁止一个三列键.删除这个异常将允许一个多列主键.现在,数据技巧是插入一个 虚排 成probe,例如,id=0。
INSERT INTO probe(probe_id, probe_when, probe_name)
VALUES( 0, '1901-01-01 00:00:00', 'Dummy probe');
现在UPDATE 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, ...);
你可以在空间和时间之间选择一个任意的阈值。现在,你已经对整张表做了四次索引。这显然会消耗大量的空间。
你可以从索引中删除一些数据,以换取更快的运行时间。
value
的所有索引中。但是,这样一来,除了在索引中进行查找外,对数据的查找也变得很有必要。(sample, gene)
或 (sample, probe)
. 这就消除了一个完整的数据覆盖,同时仍然允许您使用 sample
部分,适用于有条件的查询 sample
和删除的栏目。同样,你删除的案例就没有之前那么快了。如果你的目标是实现最小的运行时间 不惜一切代价那么所有这些建议都不适合你。我不认为现在PostgreSQL的世界里有什么可以解决你的问题。
由于你的数据很简单,而且你的用例受到限制,你可以考虑PostgreSQL以外的解决方案。特别是,你基本上只想要一个B-Tree数据结构。(或多个。)有 其他解决方案 来构建这样的数据结构,例如。QDBM. 不过,你还是需要建立多个这样的结构来优化你选择的每种类型。可实现的空间节省我认为不是很高--基本上,你可以摆脱数据,但没有索引。因此,你大概可以节省你当前存储大小的15,但代价是你的软件生态系统的功能受限和额外的复杂性。
你必须决定你需要什么,你想要什么,以及你想为这些目标牺牲什么。考虑到我在这里写下的内容,我会坚持使用PostgreSQL。