Flo*_*ris 6 sql database postgresql join
我正在努力优化LEFT JOIN针对两个非常大的表的简单性,到目前为止,这些表已经花费了大约12个小时来完成和持续.
这是执行计划:
Gather (cost=1001.26..11864143.06 rows=8972234 width=133)
Workers Planned: 7
-> Nested Loop Left Join (cost=1.26..10773657.51 rows=1281748 width=133)
-> Parallel Index Scan using var_case_aliquot_aliquot_ind on var_case_aliquot vca (cost=0.56..464070.21 rows=1281748 width=103)
-> Index Scan using genotype_pos_ind on snv_genotypes gt (cost=0.70..8.01 rows=1 width=65)
Index Cond: ((vca.chrom = chrom) AND (vca.start = start) AND (vca.end = end) AND ((vca.alt)::text = (alt)::text))
Filter: (vca.aliquot_barcode = aliquot_barcode)
Run Code Online (Sandbox Code Playgroud)
这是查询:
SELECT vca.aliquot_barcode,
vca.case_barcode,
vca.gene_symbol,
vca.variant_classification,
vca.variant_type,
vca.chrom,
int4range(vca.start::integer, vca."end"::integer, '[]'::text) AS pos,
vca.alt,
gt.called AS mutect2_call,
gt.ref_count,
gt.alt_count,
gt.read_depth,
gt.called OR
CASE
WHEN (gt.alt_count + gt.ref_count) > 0 THEN (gt.alt_count::numeric / (gt.alt_count + gt.ref_count)::numeric) > 0.20
ELSE false
END AS vaf_corrected_call
FROM analysis.var_case_aliquot vca
LEFT JOIN analysis.snv_genotypes gt ON vca.aliquot_barcode = gt.aliquot_barcode AND vca.chrom = gt.chrom AND vca.start = gt.start AND vca."end" = gt."end" AND vca.alt::text = gt.alt::text
Run Code Online (Sandbox Code Playgroud)
这两个表是非常大的:vca和gt900万(2 GB)和1.3十亿行(346 GB),分别.
我创建vca(MATERIALIZED VIEW)的唯一目的是执行此连接.本质上,它是一个连接表,只有1:1匹配左连接所需的字段,然后是一些额外的元数据.正如您在查询计划中看到的那样,所有正在连接的字段都已正确编入索引.
查询本身很简单,有什么我想念的东西可以加快它吗?我不认为有某种方法可以使用WHERE吗?
我可以在postgres设置中调整一些可能有帮助的东西吗?目前我有以下内容:
shared_buffers = 4096MB
effective_cache_size = 20GB
work_mem = 64MB
maintenance_work_mem = 4096MB
max_wal_size = 4GB
min_wal_size = 128MB
checkpoint_completion_target = 0.9
max_worker_processes = 16
max_parallel_workers_per_gather = 8
max_parallel_workers = 16
Run Code Online (Sandbox Code Playgroud)
更新12/12:
表DDL:
CREATE TABLE analysis.snv_genotypes (
aliquot_barcode character(30) NOT NULL,
chrom character(2) NOT NULL,
start bigint NOT NULL,
"end" bigint NOT NULL,
alt character varying(510) NOT NULL,
genotype character(3),
read_depth integer,
ref_count integer,
alt_count integer,
called boolean
);
ALTER TABLE ONLY analysis.snv_genotypes
ADD CONSTRAINT genotype_pk PRIMARY KEY (aliquot_barcode, chrom, start, "end", alt);
CREATE INDEX called_ind ON analysis.snv_genotypes USING btree (called);
CREATE INDEX genotype_pos_ind ON analysis.snv_genotypes USING btree (chrom, start, "end", alt);
CREATE MATERIALIZED VIEW analysis.var_case_aliquot AS
SELECT var_case_aliquot.aliquot_barcode,
var_case_aliquot.case_barcode,
var_case_aliquot.chrom,
var_case_aliquot.start,
var_case_aliquot."end",
var_case_aliquot.alt,
var_case_aliquot.gene_symbol,
var_case_aliquot.variant_classification,
var_case_aliquot.variant_type,
var_case_aliquot.hgvs_p,
var_case_aliquot.polyphen,
var_case_aliquot.sift
FROM var_case_aliquot
WITH NO DATA;
CREATE INDEX var_case_aliquot_aliquot_ind ON analysis.var_case_aliquot USING btree (aliquot_barcode);
CREATE INDEX var_case_aliquot_pos_ind ON analysis.var_case_aliquot USING btree (chrom, start, "end", alt);
Run Code Online (Sandbox Code Playgroud)
更广泛的DDL:https://rextester.com/JRJH43442
更新12/13:
为了澄清,我在CentOS 7.3上使用Postgres 10.5 w/16内核和32 GB内存.查询现在已经运行了24小时而没有任何结果.
检查状态似乎wait_event_type是IO.这是否意味着查询正在刮擦/写入临时空间?这可以解释缓慢吗?
+------------------+---------------+---------------+---------------+---------------+-----------------+--------------+--------+-------------+--------------+
| application_name | backend_start | xact_start | query_start | state_change | wait_event_type | wait_event | state | backend_xid | backend_xmin |
+------------------+---------------+---------------+---------------+---------------+-----------------+--------------+--------+-------------+--------------+
| psql | 12/12/18 8:42 | 12/12/18 8:42 | 12/12/18 8:42 | 12/12/18 8:42 | IO | DataFileRead | active | 22135 | 22135 |
+------------------+---------------+---------------+---------------+---------------+-----------------+--------------+--------+-------------+--------------+
Run Code Online (Sandbox Code Playgroud)
我有很多可用的资源:
$ free -h
total used free shared buff/cache available
Mem: 31G 722M 210M 5.0G 30G 25G
Swap: 3.7G 626M 3.1G
Run Code Online (Sandbox Code Playgroud)
我想提供更多内存可能会有所帮助吗?有没有办法优化需要更多内存的查询?
来自这篇文章的评论:
您的查询正在使用
genotype_pos_ind并过滤aliquot_barcode。尝试删除(暂时)genotype_pos_ind,如果这不起作用,请搜索如何强制使用索引。
您的查询应该genotype_pk改为使用。
根据您的说法,可能有很多记录具有相同的aliquot_barcode、chrom、start和值end,因此 RDBMS 将花费很长时间来过滤每个aliquot_barcode。
如果对您来说仍然太长,您可以尝试我的旧答案,我将保留该答案以供进一步参考:
不幸的是,我无法优化您的查询:有太多的事情需要考虑。构建包含 13 个字段的 900 万条记录的结果可能太多:可能会发生交换,您的操作系统将不允许这么多的内存分配,同时还进行(写在真正的答案之前......)JOIN等..
我曾经优化过一些由 15 个表(大约 1000 万条记录)组成的查询。SELECT这种规模的任务在合理的时间内(少于 10 小时)是不可能完成的。
我没有任何 RDBMS 来测试我所说的。另外,我已经半年没有执行任何 SQL 了:p 查找为什么花费这么多时间(如您所问)将非常耗时,因此这里是原始问题的另一个解决方案。
我采用的解决方案是制作临时表:
tmp_analysis,其字段与您的字段相同SELECT+ 一些实用程序字段:一个 ID 字段(tmp_ID,一个大整数),一个用于检查记录是否已更新的布尔值(tmp_updated),以及用于检查记录何时更新的时间戳(tmp_update_time)。当然,所有字段都具有相同的数据类型,来自您的原始字段SELECT(来自vca和gt)
vca:暂时使用null(或任何其他默认值,如果不能的话)字段。gt设置tmp_updated为假。使用简单count()的主键。
使用 aWHERE而不是 a JOIN:
UPDATE tmp_analysis as tmp -- I don't think you need to use a schema to call tmp_analysis
SET tmp_update = true,
tmp_update_time = clock_timestamp(),
tmp.mutect2_call = gt.called
gt.ref_count,
gt.alt_count,
gt.read_depth,
gt.called = -- ... (your CASE/WHEN/ELSE/END should work here)
FROM
analysis.snv_genotypes gt
WHERE --JOIN should work too
tmp.aliquot_barcode = gt.aliquot_barcode AND
tmp.chrom = gt.chrom AND
vca.start = gt.start AND
tmp."end" = gt."end" AND
tmp.alt::text = gt.alt::text
Run Code Online (Sandbox Code Playgroud)
我说你应该EXISTS出于性能原因使用,但我错了,因为我认为你不能从条件内部检索字段EXISTS。可能有一种方法可以告诉 Postgresql 这是一对一的关系,但我不确定。无论如何,索引
SELECT你的tmp_analysis表获取了你的记录!一些注意事项:
例如,使用该tmp_ID字段将更新次数限制为 10 000,然后检查第三个查询 ( UPDATE) 的执行计划:您应该对临时表表进行全扫描,并对gt( genotype_pk) 进行索引扫描。如果没有,请检查您的索引并搜索如何强制 PGSL 使用索引。您应该使用WHERE tmp_ID < 10000而不是LIMIT 10000. IIRCLIMIT将执行整个查询并只提供部分结果。
使用分段查询tmp_ID并(如您所说)使用循环语句来UPDATE一次查询 100 000 条或更少的记录(再次使用where tmp_ID < x AND tmp_ID > y)。再次检查执行计划:全扫描应该受到tmp_id索引扫描之前的限制。不要忘记在此字段上添加索引(如果它还不是主键)。
用于BEGIN/END TRANSACTION封装所有查询,并TEMPORARY TABLE打开该选项CREATE TABLE tmp_analysis,以便在执行查询后不必清理 tmp_analysis。
在循环内使用事务,如果再次冻结则停止它。然后您可以稍后使用较小的循环大小恢复它。
您可以使用 a 在一个查询中执行步骤 1 和 2 INSERT .. AS .. SELECT,但我不记得如何为 中的字段设置数据类型gt,因为它们将被设置为 null。通常情况下,整体上应该会快一点。
没有循环的查询仍然需要超过 10 个小时,停止它并检查 tmp_update_time 以查看执行时间如何演变,也许它会给你一个关于为什么原始查询不起作用的线索。PGSQL 上有多个配置选项来限制 RAM 使用、磁盘使用、线程。您的操作系统可能会设置自己的限制,并检查磁盘交换、CPU 缓存使用情况等(我认为您已经完成了其中一些操作,但我没有检查)
| 归档时间: |
|
| 查看次数: |
684 次 |
| 最近记录: |