如何加快查询 >600Mio 行?

问题描述 投票:0回答:2

我的数据库有大约 600Mio 条目我想要查询(Pandas 太慢了)。该本地 dbSNP 仅包含 rsID 和基因组位置。我用过:

import sqlite3
import gzip
import csv

rsid_db = sqlite3.connect('rsid.db')

rsid_cursor = rsid_db.cursor()

rsid_cursor.execute(
"""
CREATE TABLE rsids (
rsid TEXT,
chrom TEXT,
pos INTEGER,
ref TEXT,
alt TEXT
)
"""
)

with gzip.open('00-All.vcf.gz', 'rt') as vcf: # from https://ftp.ncbi.nih.gov/snp/organisms/human_9606/VCF/00-All.vcf.gz
    reader = csv.reader(vcf, delimiter="\t")
    i = 0
    for row in reader:
        if not ''.join(row).startswith('#'):
            rsid_cursor.execute(
            f"""
            INSERT INTO rsids (rsid, chrom, pos, ref, alt)
            VALUES ('{row[2]}', '{row[0]}', '{row[1]}', '{row[3]}', '{row[4]}');
            """
            )
            i += 1
            if i % 1000000 == 0:
                print(f'{i} entries written')
                rsid_db.commit()

rsid_db.commit()

rsid_db.close()

我想查询多个 rsID 并获取它们的基因组位置和改变(查询

rsid
并获取
chrom
pos
ref
alt
rsid
)。一个条目看起来像:

rsid 位置 参考 替代
rs537152180 1 4002401 G A、C

我查询使用:

import sqlite3
import pandas as pd


def query_rsid(rsid_list,
               rsid_db_path='rsid.db'):

    with sqlite3.connect(rsid_db_path) as rsid_db:

        rsid_cursor = rsid_db.cursor()
        rsid_cursor.execute(
        f"""
        SELECT * FROM rsids
        WHERE rsid IN ('{"', '".join(rsid_list)}');
        """
        )

        query = rsid_cursor.fetchall()

    return query

无论输入多少条,大约需要1.5分钟。有没有办法加快速度?

python sql sqlite query-optimization
2个回答
2
投票

其他人建议将

rsid
列定义为主键,或者在其上创建唯一索引。这是个好主意。

另一件事:

rsid IN ('dirty','great','list','of',items')
可能会使用所谓的skip-scan来获取结果。 如果您的
rsid_list
非常大,或者它提取了词汇上广泛分离的值,那么您可以通过将列表中的项目放入临时表中然后执行

来获得好处
SELECT rsids.*
  FROM rsids
  JOIN temp_rsids_list ON rsids.rsid = temp_rsids_list.rsids

获得更高效的查找。

我会这样声明表格:

CREATE TABLE rsids (
  rsid TEXT PRIMARY KEY COLLATE BINARY,
  chrom TEXT,
  pos INTEGER,
  ref TEXT,
  alt TEXT
) WITHOUT ROWID

COLLATE BINARY
是默认值。但是,显示它仍然很有帮助,因为您预先知道您不希望在该列上进行不区分大小写的匹配。这将提醒未来的你和你的同事这项重要的优化。

WITHOUT ROWID
告诉 SQLite 将表组织为所谓的“聚集索引”,其中其他值与易于搜索的主键一起存储。

如果您可以将主键设置为 INTEGER,那么出于性能考虑,这是一个好主意。


1
投票

您可以在

rsID
列上创建索引:

CREATE UNIQUE INDEX idx_rsid
ON rsids(rsid);

关键字

UNIQUE
仅当
rsid
的值唯一时才能使用。正如您所说,
rsid
是您的主键,因此根据定义它是唯一的。

© www.soinside.com 2019 - 2024. All rights reserved.