Большой SELECT с SQLite - PullRequest
       20

Большой SELECT с SQLite

0 голосов
/ 05 октября 2011

Я рад опубликовать свой первый вопрос сегодня.Во-первых, прошу прощения за мой плохой английский.

Я использую SQLite внутри кода Python для какой-то простой системы управления большими файлами.Конкретно, у меня есть большой плоский файл (скажем, 100 миллионов строк), который я хочу отсортировать, используя значения 3 столбцов (которые являются целыми числами), чтобы я мог перебрать его и выполнить некоторые вычисления.

Вот почему я использовал SQLite с большим SELECT ... ORDER BY (с индексом в одном столбце).Так как этот большой SELECT слишком требователен к памяти, мне нужно вызывать его несколько раз с некоторыми OFFSET и LIMIT.

Я мог бы использовать сортировку Linux, но я хочу, чтобы он не зависел от платформы.

Пока что он работает нормально (пока правильно настроена PRAGMA), но медленно.Есть ли у вас какие-либо советы, чтобы оптимизировать это?Может быть, использовать SQLite просто глупо ...

Большое спасибо за любые предложения, комментарии и т. Д.


Если вам нужны подробности о базе данных, команды выглядят так::

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)

1 Ответ

2 голосов
/ 07 октября 2011

Я написал несколько примеров сценариев, которые создают вашу базу данных и просматривают все ее элементы. И, похоже, работает намного быстрее, чем вы написали в комментариях. Вы уверены, что доступ к базе данных является узким местом? Возможно, в вашем сценарии вы делаете что-то большее, и это занимает так много времени.

Я проверил 2 базы данных SQLite и MongoDB с 5 миллионами элементов. Для вставки SQLite все строки заняли ~ 1200 секунд, а выделение их - около 300 секунд. MongoDB был быстрее и вставка заняла ~ 400 секунд при выборе менее 100 секунд.

Пожалуйста, проверьте ваш код с моими образцами и убедитесь, что ваш выбор похож. Я использовал курсор вместо LIMIT / OFFSET. Если это все равно не поможет, то я думаю, что MongoDB стоит того. У него есть один недостаток - для поддержки большой базы данных (как у вас) требуется 64-битная ОС. Если вы использовали его раньше, вот краткое руководство по установке для Windows:

А вот и мои тестовые скрипты python 3.x для SQLite

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)
...