如何选择索引一系列数据库的正确方法?

时间:2019-07-25 21:50:12

标签: sql postgresql

我正在建立一个具有相互关联的表的数据库,问题是我使用的索引方法似乎犯了某些错误,因为某些索引引用了表之间的不同行。

我有一个遗传标记数据集,具有1'405.301(SNPs)行和3092列(基因型),每个SNP均由染色体,其内部位置以及具有SNP的其他等位基因识别。

我尝试将整个数据集上载到表中,但超出了psql中表的最大列限制,因此我将数据集分为一系列子集。每个子集都有某些列,另一些则可以帮助我识别每一行(SNP)。因此,我编写了一个python sqlachemy脚本,该脚本使用与数据集对应子集相同的列名称创建一个空表。之后,我使用psql命令COPY转储对应表的每个子集,并为每个表创建了一个自动增量索引作为主键。

当我在不同表的数据之间进行比较时出现问题,因为索引引用了表之间的不同行

这是转储子集并设置每个表的索引的psql代码

COPY p11 FROM '/home/pybonacci/Documentos/.../p11.csv' WITH (HEADER true, format csv, DELIMITER E'\t');

ALTER TABLE p11
  ADD COLUMN marker_id serial primary key;

我意识到使用此代码在表的某些部分中出现了索引问题

select 
    p11.marker_id, p11."ALT", p11."POS", p08.marker_id, p08."ALT", p08."POS" 
from 
    p11 
inner join 
    p08 on p08.marker_id = p11.marker_id
where 
    p11.marker_id > 1710
order by 
    p11.marker_id
limit 100

输出:

p11.marker_id    p11.ALT    p11.POS    p08.marker_id    p08.ALT    p08.POS
1716             T          390961     1716             T          390961
1717             G          390963     1717             G          390963
1718             A          390969     1718             A          390969
1719             T          392223     1719             AG         391838
1720             CT         392240     1720             T          391847
1721             AG         391838     1721             A          391864
1722             T          391847     1722             G          391876
1723             A          391864     1723             A          391881

我希望此查询的输出为空。

我希望清楚一点,对我的英语不好对不起

1 个答案:

答案 0 :(得分:0)

虽然不是不可能,但跨表同步自动生成的serial值可能会是一个挑战。

我将以不同的方式来处理。

表中的最大列数是您无法真正摆脱的硬限制。此外,该限制还适用于单个查询可以返回的列数。因此,即使将数据集拆分为多个表,也无法访问同一查询中的所有SNP,因为联接所有表将返回超出最大列数的结果。

因此,您需要找到其他方式来存储它。

除非您可以完全更改输入文件的结构,否则我将把该文件导入到具有单个列的表中,然后使用Postgres字符串和数组函数拆分数据。

首先将原始文件加载到仅包含一个text列的表中。

create unlogged table import_table
(
  line text
);

导入文件时,您需要使用一个字符作为分隔符,输入文件中不会出现该字符,以便copy将所有内容视为一行:

copy import_table from '....' WITH (HEADER true, format text, DELIMITER '§');

我不知道数据中是否可以出现§-您需要找到一个合适的字符。不可打印字符也可能会起作用,例如:e'\x01'

数据在那里后,您可以将行转换为数组(使用string_to_array())并分别访问每个元素(列),例如将行插入到第一个“子集”表中:

insert into p01 (marker_id, alt_1, pos_1, chromosom_1, alt_2, pos_2, chromosom_2, ...)
select c[1]::int as marker_id, 
       c[2] as alt_1, 
       c[3] as pos_1, 
       c[4] as chromosom_1, 
       c[5] as alt_2, 
       c[6] as pos_2, 
       c[7] as chromosom_2, 
       ....
from (
   select string_to_array(line, E'\t') as c
   from import_table
) t;

对于其他“子集标签”也是如此。如果需要,可以使用PL / pgSQL过程将其自动化。

但是再次:您不能将所有这些表连接在一起以得到所有结果的单一结果,因为这又将超出最大列数。

根据以后需要访问数据的方式,还有其他选项可以将所有行保留在一个表中。

一种解决方案是创建一个包含三个字段的自定义类型snp_type,然后创建一个包含1000个该类型列的表:

create type snp_type as
(
  alt text, 
  pos integer,
  chromosome text
);

create table data
( 
  marker_id integer, 
  snp_1 snp_type, 
  snp_2 snp_type, 
  snp_3 snp_type,
  ...
);

然后使用如下所示的内容从导入表中填充该表:

insert into p01 (marker_id, snp_1, snp_2, ...)
select c[1]::int as marker_id, 
       (c[2], c[3]::int, c[4])::snp_type as snp_1,
       (c[5], c[6]::int, c[7])::snp_type as snp_2,
       (c[8], c[9]::int, c[10])::snp_type as snp_3,
       ....
from (
   select string_to_array(line, E'\t') as c
   from import_table
) t;

同样,这可以使用PL / pgSQL自动执行。

一旦有了snp_type,您还可以考虑将所有这些值存储到作为该类型数组的单个列中:

create type snp_type as
(
  alt text, 
  pos integer,
  chromosome text
);
create table data
( 
  marker_id integer, 
  snps snp_type[]
);

插入内容将如下所示:

insert into p01 (marker_id, snp_1, snp_2, ...)
select c[1]::int as marker_id, 
       array
       [
          (c[2], c[3]::int, c[4])::snp_type,
          (c[5], c[6]::int, c[7])::snp_type,
          (c[8], c[9]::int, c[10])::snp_type,
          ....
       ]
from (
   select string_to_array(line, E'\t') as c
   from import_table
) t;

这也可以使用PL / pgSQL自动化


上面的所有代码只是一个粗略的草图,其中可能有错误。这样做的目的是为您提供起点和关于您可以做什么的想法。

相关问题