如何最好地索引这个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, ...);
我在 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, ...);