2011-10-05 71 views
0

我很高興今天發佈我的第一個問題。首先,請原諒我可憐的英語。與SQLite的大選擇

我在一個簡單的大文件管理系統的Python代碼裏面使用SQLite。 具體來說,我有一個很大的平面文件(比方說1億行),我想用3列(它們是整數)的值進行排序,這樣我就可以迭代它並做一些計算。

這就是爲什麼我用一個大的SELECT ... ORDER BY(帶有一列索引)的SQLite。由於這個大的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) 
+0

您是否爲這3列創建了INDEX?添加索引確實會增加排序操作的速度。但它當然有它的價格 - 數據庫會更大,插入操作會更慢。 – Zuljin

+0

我認爲只會使用一個INDEX。由於插入不是瓶頸(到目前爲止!),我會試一試。謝謝! – unamourdeswann

+0

如果3個獨立的索引將不會超過也許很好地工作,將有可能創造100多列索引,如果你的選擇是爲了總是以同樣的方式。 檢查這個答案http://stackoverflow.com/questions/179085/multiple-indexes-vs-multi-column-indexes – Zuljin

回答

2

我寫了一些示例腳本來創建您的數據庫並瀏覽其所有元素。它看起來比你在評論中寫的速度快得多。你確定數據庫訪問是一個瓶頸嗎?也許在你的劇本中你做了更多的事情,這需要很多時間。

我檢查了2個數據庫SQLite和MongoDB與5百萬個項目。 對於插入所有行的SQLite需要約1200秒,並選擇它們大約300秒。 MongoDB速度更快,插入花費了大約400秒,而選擇時間少於100秒。

請檢查您的代碼與我的樣本,並檢查您的選擇是否相似。我用光標代替LIMIT/OFFSET。 如果這仍然沒有幫助,那麼我認爲MongoDB值得一試。它有一個缺點 - 它需要64位操作系統來支持大型數據庫(像你的)。如果你使用新之前那麼這裏是最短的窗戶安裝指南「 mongod.exe --dbpath」

這裏是我的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() 
蟒蛇3.x的測試腳本

和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) 
+0

太棒了! MongoDB值得一試!謝謝你的回答。 (不幸的是,我不能爲你的答案投票,因爲我沒有聲望......)。 – unamourdeswann