大型连接表和缩放

时间:2011-08-25 07:46:22

标签: database database-design relational-database

问题

我们有一个快速增长的数据库,其中包含几个大型连接表(目前在数十亿行中),但随着这些表的增长,查询时间也受到了影响。令人担忧的是,随着更多数据被添加到由这些连接表链接的表中,连接表将继续以更快的速度增长并对查询速度产生负面影响。

背景

我正在处理存储基因组信息的数据库。对应于存在DNA变异的基因座的许多标记(~3百万)与在这些基因座处确定其基因型的个体相关联。每个标记都有许多可能的基因型,每个人都必须拥有一个基因型。

当前实施

当数据库(postgresql)仍然很小时,使用外键将基因型链接到标记,然后通过连接表将个体链接到它们的基因型没有问题。这样,很容易查找所有个体的基因型或查找具有特定基因型的所有个体。

下表列出了这些表格的精简版本:

                                        Table "public.genotypes"
      Column      |            Type             |                       Modifiers                        
------------------+-----------------------------+--------------------------------------------------------
 id               | integer                     | not null default nextval('genotypes_id_seq'::regclass)
 ref_variation_id | integer                     | 
 value            | character varying(255)      |  
Indexes:
    "genotypes_pkey" PRIMARY KEY, btree (id)
    "index_genotypes_on_ref_variation_id" btree (ref_variation_id)


Table "public.genotypes_individuals"
    Column     |  Type   | Modifiers 
---------------+---------+-----------
 genotype_id   | integer | 
 individual_id | integer | 
Indexes:
    "index_genotypes_individuals_on_genotype_id_and_individual_id" UNIQUE, btree (genotype_id, individual_id)
    "index_genotypes_individuals_on_genotype_id" btree (genotype_id)

                                       Table "public.individuals"
    Column     |            Type             |                        Modifiers                         
---------------+-----------------------------+----------------------------------------------------------
 id            | integer                     | not null default nextval('individuals_id_seq'::regclass)
 hap_id        | character varying(255)      | 
 population_id | integer                     | 
 sex           | character varying(255)      | 
Indexes:
    "individuals_pkey" PRIMARY KEY, btree (id)
    "index_individuals_on_hap_id" UNIQUE, btree (hap_id)

现在的瓶颈是查找个人的所有基因型,并根据他们的位置对其进行排序。这经常被使用,并且比从基因型中查找个体更重要。其中一些查询的示例如下:

  • 简单查找所有个体的基因型

    SELECT * FROM“genotypes”INNER JOIN“genotypes_individuals”ON“genotypes”.id =“genotypes_individuals”.genotype_id WHERE(“genotypes_individuals”.individual_id = 2946)

  • 通常,虽然这是有限的,因为有很多基因型。我们通常只对特定染色体上的那些感兴趣。

    SELECT * FROM“genotypes”INNER JOIN“genotypes_individuals”ON“genotypes”.id =“genotypes_individuals”.genotype_id WHERE(“genotypes_individuals”.individual_id = 2946)AND(“genotypes”.ref_variation_id IN(37142,37143 ,. ..))

  • 我们还需要偶尔走另一条路。

    SELECT * FROM“individual”INNER JOIN“genotypes_individuals”ON“persons”.id =“genotypes_individuals”.individual_id WHERE(“genotypes_individuals”.genotype_id = 53430)

每次将新个人添加到数据库时,连接表都会增加大约300万行。直观地从设计角度来看,这看起来很糟糕,因为添加新个人会降低使用现有数据的任何流程的性能。

我知道数据库旨在有效地处理大型表,但由于驱动器IO,我们已经遇到了瓶颈。单个查询仍然无关紧要,但其中1000个快速加起来。我们可以通过将db扩展到多个驱动器来稍微缓解这个问题。但是,我想看看那里是否还有其他选择。我一直想知道是否有可能通过individual_id隔离连接表条目,这可能会使个体查找通过向连接表添加额外的单个基因型行而不受影响的基因型。或者指数已经做到了吗?

2 个答案:

答案 0 :(得分:0)

你看过table partitioning吗?

答案 1 :(得分:0)

我会考虑测试使用自然键而不是id号的模式。

您查找所有个人的基因型

SELECT * 
FROM "genotypes" 
INNER JOIN "genotypes_individuals" 
        ON "genotypes".id = "genotypes_individuals".genotype_id 
WHERE ("genotypes_individuals".individual_id = 2946 )

变为

SELECT * 
FROM genotypes_individuals
WHERE (individual_id = 2946)

有时候会更快。有时它不是。

切换到我们的生产系统上的自然键将中值性能提高了10倍。使用自然键,一些查询的运行速度提高了100倍,因为自然键消除了大量连接。有些查询运行速度也较慢。但无论如何,中位数加速都令人印象深刻。