Speeding up PostgreSQL queries (Check if entry exists in another table)

不羁的心 提交于 2020-06-27 05:15:34

问题


I need some help to improve the speed of a query.

I have 3 tables:
1- pairTable2 a 4 columns table:
- genomic_accession: grouping column (don't care for this question)
- assembly: grouping column (don't care for this question)
- product_accession: column used to search in other table
- tmpcol: column used to search in other table
2- SBPDB an 1 column table:
- product_accession: column used to search in other table
3- cacheDB an 1 column table: - product_accession: column used to search in other table

The idea is to create a boolean column called SBP in table 1 which is TRUE if the value on columns product_accession and/or tmpcol is within the unique column in SBPDB;
And, create a boolean column called SBP in table 1 which is TRUE if the value on columns product_accession and/or tmpcol is within the unique column in cacheDB.

I'm using R with DBI and dplyr as backend, then the query may look weirdo. But, the query I'm trying to do is:

SELECT "genomic_accession", 
       "assembly", 
       "product_accession", 
       "tmpcol", 
       "product_accession" IN (SELECT product_accession 
                               FROM   "cachedb") 
        OR "tmpcol" IN (SELECT product_accession 
                        FROM   "cachedb") AS "CACHE", 
       "product_accession" IN (SELECT product_accession 
                               FROM   "sbpdb") 
        OR "tmpcol" IN (SELECT product_accession 
                        FROM   "sbpdb")   AS "SBP" 
FROM   (SELECT * 
        FROM   "pairtable2" 
        LIMIT  500000) "dbplyr_031";

(check the explain)

                                       QUERY PLAN                                       
----------------------------------------------------------------------------------------
 Subquery Scan on dbplyr_031  (cost=3242.27..3846856408.45 rows=500000 width=59)
   ->  Limit  (cost=0.00..10666.17 rows=500000 width=57)
         ->  Seq Scan on "pairTable2"  (cost=0.00..781515.16 rows=36635216 width=57)
   SubPlan 1
     ->  Seq Scan on "cacheDB"  (cost=0.00..1394.91 rows=90491 width=14)
   SubPlan 2
     ->  Seq Scan on "cacheDB" "cacheDB_1"  (cost=0.00..1394.91 rows=90491 width=14)
   SubPlan 3
     ->  Materialize  (cost=0.00..7001.57 rows=276838 width=14)
           ->  Seq Scan on "SBPDB"  (cost=0.00..4265.38 rows=276838 width=14)
   SubPlan 4
     ->  Materialize  (cost=0.00..7001.57 rows=276838 width=14)
           ->  Seq Scan on "SBPDB" "SBPDB_1"  (cost=0.00..4265.38 rows=276838 width=14)
(13 rows)

So, this is just a sample of 500k rows, and after 1 hour still running. The total of rows is:

genomes=> select count(*) from "pairTable2";
  count   
----------
 36633962
(1 row)

I need at least some suggestions to figure out a better query to speed up my needs.

Example of the tables:
(1)

 genomic_accession |    assembly     | product_accession |     tmpcol     
-------------------+-----------------+-------------------+----------------
 NC_007777.1       | GCF_000013345.1 | WP_011437108.1    | WP_011437109.1
 NC_007777.1       | GCF_000013345.1 | WP_011437109.1    | WP_011437110.1
 NC_007777.1       | GCF_000013345.1 | WP_011437110.1    | WP_011437113.1
 NC_007777.1       | GCF_000013345.1 | WP_011437113.1    | WP_011437114.1
 NC_007777.1       | GCF_000013345.1 | WP_011437114.1    | WP_011437116.1
 NC_007777.1       | GCF_000013345.1 | WP_011437116.1    | WP_011437117.1
 NC_007777.1       | GCF_000013345.1 | WP_011437117.1    | WP_011437118.1
 NC_007777.1       | GCF_000013345.1 | WP_011437118.1    | WP_011437120.1
 NC_007777.1       | GCF_000013345.1 | WP_011437120.1    | WP_011437121.1
 NC_007777.1       | GCF_000013345.1 | WP_011437121.1    | WP_011437123.1
(10 rows)

(2)

 product_accession 
-------------------
 WP_005887071.1
 WP_005913801.1
 WP_002804432.1
 WP_010366489.1
 WP_012444785.1
 NP_636898.1
 WP_046342269.1
 WP_074057745.1
 WP_039420813.1
 WP_005932253.1
(10 rows)

(3)

 product_accession 
-------------------
 ABG85315.1
 ABG85570.1
 ABG86033.1
 ABG86301.1
 ABG87594.1
 ACX82524.1
 ACX83274.1
 ACX83416.1
 ADX79866.1
 ADX79880.1
(10 rows)

Example of output:

 genomic_accession |    assembly     | product_accession |     tmpcol     | CACHE | SBP 
-------------------+-----------------+-------------------+----------------+-------+-----
 NC_007899.1       | GCF_000009945.1 | WP_011457581.1    | WP_011457582.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457582.1    | WP_011457583.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457583.1    | WP_011457584.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457584.1    | WP_011457585.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457585.1    | WP_011457586.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457586.1    | WP_011457587.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457587.1    | WP_011457588.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457588.1    | WP_011457589.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457589.1    | WP_011457590.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457590.1    | WP_011457592.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457592.1    | WP_011457593.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457593.1    | WP_011457594.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457594.1    | WP_011457596.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457596.1    | WP_011457597.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457597.1    | WP_011457598.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457598.1    | WP_011457600.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457600.1    | WP_011457601.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457601.1    | WP_011457602.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457602.1    | WP_011457603.1 | f     | f
 NC_007899.1       | GCF_000009945.1 | WP_011457603.1    | WP_011457604.1 | f     | f

Thanks in advance


回答1:


This is your query:

SELECT "genomic_accession", "assembly", "product_accession", "tmpcol",
       ("product_accession" IN ( SELECT product_accession FROM "cacheDB" ) OR
        "tmpcol" IN ( SELECT product_accession FROM "cacheDB")
       ) AS "CACHE",
       ("product_accession" IN ( SELECT product_accession FROM "SBPDB" ) OR
        "tmpcol" IN ( SELECT product_accession FROM "SBPDB" ) AS "SBP"
FROM (SELECT * FROM "pairTable2" LIMIT 500000) "dbplyr_031";

I would get rid of all the double quotes. Don't create column names and table names that need to be escaped. Then, EXISTS with the right indexes often performs better:

SELECT "genomic_accession", "assembly", "product_accession", "tmpcol",
       (EXISTS (SELECT 1
                FROM "cacheDB" c
                *WHERE c.product_accession IN (pt.product_accession, pt.tmpcol ) 
               )
       ) AS CACHE,
       (EXISTS (SELECT 1
                FROM "SBPDB" s
                WHERE s.product_accession IN (pt.product_accession, pt.tmpcol ) 
               )
       ) AS SBP
FROM (SELECT * FROM "pairTable2" LIMIT 500000) pt;

Then, for performance, you want indexes on cachedb(product_accession) and sbpdb(product_accession).



来源:https://stackoverflow.com/questions/61462084/speeding-up-postgresql-queries-check-if-entry-exists-in-another-table

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!