我的数据库有大约 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分钟。有没有办法加快速度?
其他人建议将
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,那么出于性能考虑,这是一个好主意。
您可以在
rsID
列上创建索引:
CREATE UNIQUE INDEX idx_rsid
ON rsids(rsid);
关键字
UNIQUE
仅当 rsid
的值唯一时才能使用。正如您所说,rsid
是您的主键,因此根据定义它是唯一的。