2012-06-01 3 views
16

Ich habe die folgende select-Anweisung (mit sqlite3 und dem pysqlite Modul):Ist der unterbrechungsfreie Schlaf der Grund für mein Python-Programm wirklich langsam (und wenn ja, wie kann ich das lösen?)?

self.cursor.execute("SELECT precursor_id FROM MSMS_precursor "+ 
    "JOIN spectrum ON spectrum_id = spectrum_spectrum_id "+ 
    "WHERE spectrum_id = spectrum_spectrum_id "+ 
    "AND ROUND(ion_mz,9) = ? AND ROUND(scan_start_time,4) = ? "+ 
    "AND msrun_msrun_id = ?", select_inputValues) 

die 55 Sekunden in Anspruch nimmt, wenn in Python läuft. Wenn es direkt in der SQLite-Befehlszeile ausgeführt wird, dauert es nur 15 ms. Jetzt ist mir aufgefallen, dass das Python-Programm in diesem Schritt in den ununterbrochenen Ruhezustand geht (31283 ndeklein 18 0 126m 24m 3192 D 1.0 0.0 2:02.50 python, Das D in der obersten Ausgabe) und von 100% CPU auf etwa 1% CPU sinkt. Jetzt, da ich es während dieser Abfrage bemerkt habe, habe ich mir auch die oberste Ausgabe angesehen, als ich die Abfrage über here ausgeführt habe. Während dieser Zeit zeigt top auch an, dass es in den ununterbrochenen Schlaf wechselt, obwohl es zwischen R und D hin- und herwechselt und sich nur auf etwa 50% verlangsamt (es schwankt abhängig davon, ob es im D- oder R-Status ist).

Also jetzt ich denke, dass das ist, was verlangsamt meine Abfrage (bitte korrigieren Sie mich, wenn ununterbrochener Schlaf hat nichts mit Programmen Geschwindigkeit zu tun). Wenn das stimmt, wie kann ich sicherstellen, dass ein Programm diesen Status nicht erreicht?


Update 1:

Der QUERY EXPLAIN PLAN Python zurückgegeben:

(0, 0, 1, u'SCAN TABLE spectrum (~50000 rows)') 

Der QUERY EXPLAIN PLAN sqlite der Befehlszeile zurückgegeben werden:

0|0|1|SCAN TABLE spectrum (~50000 rows) 
0|1|0|SEARCH TABLE MSMS_precursor USING INDEX fk_MSMS_precursor_spectrum_spectrum_id_1 (spectrum_spectrum_id=?) (~2 rows) 

Die EXPLAIN mit Python zurückgegeben:

(0, u'Trace', 0, 0, 0, u'', u'00', None) 

Die EXPLAIN mit SQLite zurückgegeben:

0|Trace|0|0|0||00| 
1|Real|0|1|0|438.718658447|00| 
2|Real|0|2|0|692.6345000000001|00| 
3|Integer|1|3|0||00| 
4|Goto|0|39|0||00| 
5|OpenRead|1|33|0|13|00| 
6|OpenRead|0|39|0|5|00| 
7|OpenRead|2|41|0|keyinfo(1,BINARY)|00| 
8|Rewind|1|35|0||00| 
9|Column|1|8|5||00| 
10|RealAffinity|5|0|0||00| 
11|Integer|4|6|0||00| 
12|Function|2|5|4|round(2)|02| 
13|Ne|2|34|4||6a| 
14|Column|1|12|4||00| 
15|Ne|3|34|4|collseq(BINARY)|6c| 
16|Column|1|0|8||00| 
17|IsNull|8|34|0||00| 
18|Affinity|8|1|0|d|00| 
19|SeekGe|2|34|8|1|00| 
20|IdxGE|2|34|8|1|01| 
21|IdxRowid|2|7|0||00| 
22|Seek|0|7|0||00| 
23|Column|1|0|9||00| 
24|Column|2|0|10||00| 
25|Ne|10|33|9|collseq(BINARY)|6b| 
26|Column|0|1|5||00| 
27|RealAffinity|5|0|0||00| 
28|Integer|9|6|0||00| 
29|Function|2|5|11|round(2)|02| 
30|Ne|1|33|11||6a| 
31|Column|0|0|13||00| 
32|ResultRow|13|1|0||00| 
33|Next|2|20|0||00| 
34|Next|1|9|0||01| 
35|Close|1|0|0||00| 
36|Close|0|0|0||00| 
37|Close|2|0|0||00| 
38|Halt|0|0|0||00| 
39|Transaction|0|0|0||00| 
40|VerifyCookie|0|31|0||00| 
41|TableLock|0|33|0|spectrum|00| 
42|TableLock|0|39|0|MSMS_precursor|00| 
43|Goto|0|5|0||00| 

Und iostat zurückgegeben:

io-bash-3.2$ iostat 
Linux 2.6.18-194.26.1.el5 (ningal.cluster.lifesci.ac.uk)   06/04/2012 

avg-cpu: %user %nice %system %iowait %steal %idle 
      14.35 0.00 0.30 0.01 0.00 85.34 

Device:   tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn 
sda    1.16   4.55  17.22 1520566 5752802 
sda1    0.00   0.02   0.00  5074   34 
sda2    1.16   4.53  17.22 1515184 5752768 
sdb    0.00   0.02   0.00  5108   0 
dm-0    2.29   3.88  16.70 1297226 5579336 
dm-1    0.00   0.00   0.00  928   0 
dm-2    0.11   0.65   0.52  216106  173432 

Update 2

ich die Datenbank MySQL migriert und hier die Abfrage nur dauert etwa 0,001 Sekunde, , obwohl ich für alle anderen Abfragen tun werde Tatsächlich ist es langsamer als sqlite (ich habe es für sqlite optimiert, also könnte das vielleicht überraschen).

+1

Verwenden Sie die gleiche Version der SQLite-Bibliothek von Python und in der SQLite-Shell? Normalerweise ist die Python Pysqlite Version ziemlich alt. – schlenk

+0

Ja ich benutze die gleiche Version. –

+0

Können Sie überprüfen, ob die Analyse von 'EXPLAIN' für jede Abfrage die gleiche ist, die in Python und die im Befehlszeilentool? (Sie müssen wahrscheinlich ein paar benutzerdefinierte Python für dieses Debugging schreiben.) – ghoti

Antwort

0

Es gibt ein Leistungsproblem mit SQLite und Python. Lesen Sie diesen Thread für weitere Informationen. Es gibt ein paar Vorschläge - probieren Sie sie aus, es könnte funktionieren - wie zum Beispiel einen Index zu Ihren Join-Feldern hinzuzufügen oder pysqlite zu verwenden.

http://www.mail-archive.com/[email protected]/msg253067.html

+1

Ich benutze Pysqlite und ich habe Indizes auf den JOINS. Außerdem funktioniert es sowohl für MySQL als auch für Python und SQLite schnell. –

+0

Sie haben einen Index für spectrum_spectrum_id, aber ich sehe keinen auf spectrum_id der Spektrumstabelle. Das Problem hier ist spezifisch für Python + SQLite, daher ist es in Ordnung, dass es in der SQLite-Befehlszeile schnell funktioniert. Auch welche Version von Pysqlite verwendest du? – kjp

+0

Ich habe einen Index für spektrum_id der Spektrumstabelle. Meine Pysqlite-Version ist 2.6.3 –

2

Wie ich in an answer to a prior question you asked erwähnt, haben Sie den SQLite-Modul apsw einen Versuch geben? From the website:

APSW ist ein Python-Wrapper für die SQLite Motor relationale Datenbank eingebettet ist. Im Gegensatz zu anderen Wrappern wie pysqlite konzentriert es sich auf als eine minimale Schicht über SQLite, die versucht, die komplette SQLite API in Python zu übersetzen. Die Dokumentation enthält einen Abschnitt zu die Unterschiede zwischen APSW und Pysqlite.

Ich versuchte es selbst, und es scheint in der Tat besser zu reflektieren, wie SQL-Anweisungen von der „echten“ Sqlite ausgeführt werden (das heißt der Client oder der C-Bibliothek).

+0

Ich habe das nicht versucht, da ich nicht herausfinden kann, wie man es gegen eine bereits bestehende Verschmelzung statt der Standardinstallation installiert oder mit -fetch einen neuen Download –

+0

Welchen Fehler hast du bekommen, wenn man einen neuen holt? –

+0

Ich bin der Autor von APSW. Wenn Sie Ihre vorhandenen SQLite-Bibliotheken verwenden möchten, lassen Sie den Parameter --fetch beim Erstellen einfach weg. Dies ist dokumentiert unter http://apidoc.apsw.googlecode.com/hg/build.html#finding-sqlite-3 –

Verwandte Themen