2011-10-05 3 views
0

Je suis heureux de poster ma première question aujourd'hui. D'abord, excusez mon pauvre anglais. J'utilise SQLite dans un code Python pour un système de gestion de gros fichiers facile. Concrètement, j'ai un gros fichier plat (disons, 100 millions de lignes) que je veux trier en utilisant les valeurs de 3 colonnes (qui sont des entiers), de sorte que je puisse parcourir et faire des calculs.Big SELECT avec SQLite

C'est pourquoi j'ai utilisé SQLite avec un grand SELECT ... ORDER BY (avec un index sur une colonne). Comme ce gros SELECT est trop gourmand en mémoire, j'ai besoin de l'appeler plusieurs fois, avec quelques OFFSET et LIMIT.

Je pourrais utiliser le tri Linux, mais je veux qu'il soit indépendant de la plateforme. Jusqu'à présent, cela fonctionne bien (à condition que les bons PRAGMA soient correctement réglés), mais lentement. Avez-vous des conseils pour optimiser cela? Peut-être en utilisant SQLite est tout simplement stupide ...

Merci beaucoup pour toute suggestion, commentaire, etc.


Si vous voulez des détails sordides sur la base de données, les commandes sont comme:

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

Avez-vous créé des INDEX pour ces 3 colonnes? L'ajout d'index augmente réellement la vitesse des opérations de tri. Mais bien sûr, il a son prix - la base de données sera plus grande et l'insertion sera plus lente. – Zuljin

+0

Je pensais qu'un seul INDEX serait utilisé. Depuis l'insertion n'est pas le goulot d'étranglement (jusqu'à présent!), Je vais essayer. Merci! – unamourdeswann

+0

Si 3 index séparés ne fonctionnent pas bien, il sera peut-être possible de créer 1 index multi-colonnes si votre SELECT est toujours de la même manière. Cochez cette réponse http://stackoverflow.com/questions/179085/multiple-indexes-vs-multi-column-indexes – Zuljin

Répondre

2

J'ai écrit un exemple de script qui crée votre base de données et passe en revue tous ses éléments. Et il semble que cela fonctionne beaucoup plus vite que votre écrit dans les commentaires. Êtes-vous sûr que l'accès à la base de données est un goulot d'étranglement? Peut-être que dans votre script vous faites quelque chose de plus et cela prend tellement de temps.

J'ai vérifié 2 bases de données SQLite et MongoDB avec 5 millions d'éléments. Pour SQLite, l'insertion de toutes les lignes a pris ~ 1200 secondes et leur sélection autour de 300 secondes. MongoDB était plus rapide et l'insertion prenait ~ 400 secondes tout en sélectionnant moins de 100 secondes.

Veuillez vérifier votre code avec mes échantillons et vérifiez si votre sélection est similaire. J'ai utilisé le curseur au lieu de LIMIT/OFFSET. Si cela n'aide pas, alors je pense que MongoDB vaut le coup. Il a un inconvénient: il nécessite un système d'exploitation 64 bits pour prendre en charge une base de données volumineuse (comme la vôtre). Si vous utilisez plus récent avant est alors ici guide d'installation le plus court pour les fenêtres:

Et voici mes scripts de test 3.x python pour 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() 

et pour 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

Super! MongoDB vaut le coup! Merci pour votre aimable réponse. (Malheureusement, je ne peux pas voter pour votre réponse car je n'ai pas encore de réputation ...). – unamourdeswann