【问题标题】:Big SELECT optimization大SELECT优化
【发布时间】:2011-12-01 08:08:24
【问题描述】:

我在 Python 中使用 SQLite 作为大型文件管理系统。我有一个大的平面文件(1 亿行),我想使用 3 列(整数)的值对其进行排序,以便我可以迭代并进行一些计算。

我使用带有大 SELECT ... ORDER BY 的 SQLite(在一列上有一个索引)。由于这个大的SELECT 占用太多内存,我需要多次调用它(使用OFFSETLIMIT)。

我可以使用 Linux 排序,但我希望它独立于平台。它工作正常(只要正确设置了正确的 PRAGMA),但速度很慢。如何优化?

命令如下:

PRAGMA journal_mode = OFF
PRAGMA synchronous = 0
PRAGMA locking_mode = EXCLUSIVE
PRAGMA count_change = OFF
PRAGMA temp_store = 2
CREATE TABLE tmpTranscripts_arm_3R_transcripts (id INTEGER PRIMARY KEY, name varchar(255), chromosome varchar(255), start int(11), end int(11), direction tinyint(4), tags varchar(1023), bin int(11), exons varchar(10000))
CREATE INDEX 'iTranscript_arm_3R_14943' ON 'tmpTranscripts_arm_3R_transcripts' (start, end, direction)
INSERT INTO tmpTranscripts_arm_3R_transcripts (name, chromosome, start, end, direction, tags, bin, exons) VALUES ('SRR060644.1', 'arm_3R', 11450314, 11450337, -1, 'feature=transcript;bestRegion=(self);nbGaps=0;nbMismatches=0;ID=SRR060644.1;identity=100.0', 300011450, '')
(this, more than 10 millions times)
SELECT * FROM tmpTranscripts_arm_3R_transcripts ORDER BY start, end, direction LIMIT 0, 10000
(this, as much as needed)

【问题讨论】:

  • 您是否为这 3 列创建了索引?添加索引确实提高了排序操作的速度。但它当然有它的代价——数据库会更大,插入操作会更慢。
  • 如果 3 个单独的索引不能很好地工作,那么如果您的 SELECT 始终以相同的方式排序,则可能创建 1 个多列索引。检查这个答案stackoverflow.com/questions/179085/…
  • 好吧,它似乎并没有更好地工作......它需要大约 8 小时来迭代“仅”1000 万行......我尝试了两种解决方案......另一个想法?

标签: sqlite select sql-order-by pysqlite


【解决方案1】:

我编写了一些示例脚本来创建您的数据库并遍历其所有元素。它看起来比你在 cmets 中写的要快得多。您确定数据库访问是瓶颈吗?也许在你的脚本中你做了更多的事情,这需要很多时间。

我检查了 2 个数据库 SQLite 和 MongoDB,其中包含 500 万个项目。 对于 SQLite,插入所有行大约需要 1200 秒,选择它们大约需要 300 秒。 MongoDB 更快,插入大约需要 400 秒,而选择不到 100 秒。

请用我的示例检查您的代码,并检查您的选择是否相似。我使用游标而不是 LIMIT/OFFSET。 如果这仍然没有帮助,那么我认为 MongoDB 值得一试。它有一个缺点 - 它需要 64 位操作系统来支持大型数据库(如您的)。如果您之前使用过它,那么这里是 Windows 的最短安装指南:

这是我用于 SQLite 的 python 3.x 测试脚本

import sqlite3
from time import time

conn = sqlite3.connect('test.dbase')

c = conn.cursor()

c.execute("""PRAGMA journal_mode = OFF""")
c.execute("""PRAGMA synchronous = 0""")
c.execute("""PRAGMA locking_mode = EXCLUSIVE""")
c.execute("""PRAGMA count_change = OFF""")
c.execute("""PRAGMA temp_store = 2""")

c.execute("""CREATE TABLE tmpTranscripts_arm_3R_transcripts (id INTEGER PRIMARY KEY, name varchar(255), chromosome varchar(255), start int(11), end int(11), direction tinyint(4), tags varchar(1023), bin int(11), exons varchar(10000))""")
c.execute("""CREATE INDEX 'iTranscript_arm_3R_14943' ON 'tmpTranscripts_arm_3R_transcripts' (start, end, direction)""")

t1 = time()

for i in range(0, 5000000):
    c.execute("""INSERT INTO tmpTranscripts_arm_3R_transcripts (name, chromosome, start, end, direction, tags, bin, exons) VALUES ('SRR060644.1', 'arm_3R', %d, %d, %d, 'feature=transcript;bestRegion=(self);nbGaps=0;nbMismatches=0;ID=SRR060644.1;identity=100.0', 300011450, '')""" % ((i+123)%352, (i+523)%422, (i+866)%536))
    if(not i%10000):
        print("Insert:", i)

t2 = time()
print("Insert time", t2-t1)

conn.commit()

t1 = time()
c.execute("""SELECT * FROM tmpTranscripts_arm_3R_transcripts ORDER BY start, end, direction""")

i = 0
for row in c:
    a = row[0]
    if(not i%10000):
        print("Get:", i, row)
    i+=1

t2 = time()
print("Sort time", t2-t1)

c.close()

对于 MongoDB

from pymongo import Connection
from pymongo import ASCENDING, DESCENDING
from time import time

connection = Connection()
connection = Connection('localhost', 27017)
db = connection['test-database']
collection = db['test-collection']
posts = db.posts

posts.create_index([("start", ASCENDING), ("end", ASCENDING), ("direction", ASCENDING)])

t1 = time()

for i in range(0, 5000000):
    post = { "name": 'SRR060644.1',
            "chromosome": 'arm_3R',
            "start": (i+123)%352,
            "end": (i+523)%422,
            "direction": (i+866)%536,
            "tags": 'feature=transcript;bestRegion=(self);nbGaps=0;nbMismatches=0;ID=SRR060644.1;identity=100.0',
            "bin": 300011450,
            "exons": ''}

    posts.insert(post)

    if(not i%10000):
        print("Insert:", i)

t2 = time()
print("Insert time", t2-t1)

t1 = time()

i = 0
for post in posts.find().sort([("start", ASCENDING), ("end", ASCENDING), ("direction", ASCENDING)]):
    if(not i%10000):
        print("Get:", i, post)
    i+=1

t2 = time()
print("Sort time", t2-t1)

【讨论】:

    猜你喜欢
    • 2021-12-21
    • 2016-07-27
    • 1970-01-01
    • 2013-01-03
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    相关资源
    最近更新 更多