Frage zu sqlite und Prüfung, ob eine ID schon in der Datenbank steht

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Benutzeravatar
pixewakb
User
Beiträge: 1408
Registriert: Sonntag 24. April 2011, 19:43

Ich habe eine sqlite-Datenbank mit einer Größe von etwa 700 MB. Für eine Prüfung neuer Daten lade ich alle IDs aus der Datenbank ins Programm und prüfe dann jeweils, ob die ID schon in der Datenbank steht (den Quelltext muss ich mir in den kommenden Wochen noch mal ansehen, lief jetzt längere Zeit ohne Probleme). Momentan - wenn ich den logfiles glauben darf - liegt zwischen Initialisierung und Start der eigentlichen Arbeit schon mal eine Viertelstunde, könnte das an der Datenmenge liegen? Gibt es eine effizientiere Lösung für mein Problem, z. B. Datenhaltung der IDs in einem csv-file oder gibt es da eine normale Standard-Lösung?

Schuldigung, dass ich eher wenig Infos poste; ich hoffe erst einmal nur so auf eine grobe Antwort. (Momentan habe ich einen Arbeitsberg und deutlichen Rückstand, ich kann in den Quelltext erst in den kommenden Wochen wieder einmal reinschauen.) :oops:
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@pixewakb: was erwartest Du? Ohne Quellcode kann niemand sagen, was passiert, bis irgendetwas anderes passiert? Auch bei 700MB Daten lesen ist eine Viertelstunde ziemlich lang.
Benutzeravatar
pixewakb
User
Beiträge: 1408
Registriert: Sonntag 24. April 2011, 19:43

Sirius3 hat geschrieben:@pixewakb: was erwartest Du? Ohne Quellcode kann niemand sagen, was passiert, bis irgendetwas anderes passiert? Auch bei 700MB Daten lesen ist eine Viertelstunde ziemlich lang.
Als Antwort reicht mir das schon. Würdest du auch alle IDs auslesen oder würdest du das bei so einer Aufgabe anders lösen? Ich packe das in eine Liste und prüfe gegen die Liste, nicht mehr gegen die Datenbank.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@pixewakb: was prüfst Du denn? Ob die ID existiert? Ob der Eintrag identisch ist? Und was passiert dann, wenn eine der Bedingungen zutrifft?
Benutzeravatar
pixewakb
User
Beiträge: 1408
Registriert: Sonntag 24. April 2011, 19:43

Ich habe eine Prüfliste, die ich beim Start aus der Datenbank lade und die dann alle IDs enthält. Ich frage dann Ergebnisseiten im Netz ab, wobei jeder Datensatz dort ebenfalls über eine feste, eindeutige ID verfügt. Ich rufe die HTML-Seite ab und kontrolliere, ob ich die ID bereits in der Liste habe, falls ja, gehe ich weiter, falls nein, werte ich die HTML-Seite aus und lade den Datensatz in die Datenbank und füge die ID der Liste hinzu.

Die ID hat mal irgendwann mit 1 begonnen und jetzt sind wir m. E. im sechsstelligen Bereich. Ich überlege, im Kern nur die letzten 10.000 IDs in der Liste zu halten, aber bin mir unsicher, ob das einen Gewinn an Geschwindigkeit oder Stabilität bringt. Momentan läuft das Tool nicht mehr richtig, weil sich das Design der Website geändert hat -> muss ich kommende Woche fixen.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn die IDs monoton steigend sind, dann reicht ja, das Maximum abzufragen. Und auch das Abfragen von 1Mio IDs müßte in Sekunden erledigt sein. Ist das Problem nicht eher die HTTP-Abfrage?
Benutzeravatar
pixewakb
User
Beiträge: 1408
Registriert: Sonntag 24. April 2011, 19:43

Danke für die Einschätzung!

Die HTTP-Abfragen laufen m. E. kontinuierlich ohne Verzögerungen durch; ich bin kein gelernter Programmierer (weder Ausbildung noch Studium) und vor dem Hintergrund bin ich für [d]eine Einschätzung sehr (!) dankbar. Ich gucke es mir Montag an. Danke!
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

HTTP Abfragen kosten grundsätzlich sehr viel Zeit, zumindest relativ zu anderen Operationen wie auf Daten auf einer Festplatte oder im Speicher zuzugreifen.

Du solltest auf jedenfall schauen ob du diese Abfragen nicht parallelisieren kannst. Falls der Code halbwegs brauchbar strukturiert ist, sollte man da relativ schnell schon etwas Zeit durch die Nutzung eines Thread Pools. In der Standard Library gibt es für ein ähnliches Problem ein Beispiel.
Benutzeravatar
pixewakb
User
Beiträge: 1408
Registriert: Sonntag 24. April 2011, 19:43

Code: Alles auswählen

import sqlite3

def get_newsid_textid_from_db(PATH_db):
    # Erhalte (news_id, textid)
    # get lists of tuples with newsid and textid from db
    conn = sqlite3.connect(PATH_db)
    c = conn.cursor()
    c.execute("SELECT news_id, textid FROM news ORDER BY news_id")
    results = c.fetchall()
    conn.close()
    return results
Ich habe das logging in der betreffenden Datei verfeinert und häufig hängt er sich bei dieser Funktion auf. Die Tabelle news in einer inzwischen 750 MB großen Datenbank enthält zu News-Artikeln in vollem Text eben auch Metadaten und eben auch diese newsids und die textids. Irgendwo scheint er sich zu verschlucken, jedenfalls kann eine Anfrage auf meinem Rechner schon mal so 2 Minuten dauern (optimaler Fall) oder auch mal zum Einfrieren des Skrips führen, d. h. es passiert nichts und im Taskmanager wird der Dienst mit einer Beanspruchung des Arbeitsspeichers so zwischen 3000 und 5000 KB angezeigt. Ich weiß dann schon, dass es nicht mehr richtig durchläuft.

Meine Fragen: Wenn ich das "ORDER BY news_id" weglasse und dann die results im eigentlichen Python-Quellcode sortiere, könnte das einen Geschwindigkeitsvorteil bringen? (Das ist meine erste Datenbank überhaupt, mit der ich arbeite.) Sollte ich es überhaupt sortieren? Ich prüfe, ob ein bestimmtes Bündel aus (news_id, textid) schon in der Datenbank ist, wenn nicht, speichere ich es, sonst gehe ich zur nächsten Nachricht weiter.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@pixewakb: Du lädst Dir ja auch die gesamte Datenbank in den Speicher. Ob das sinnvoll ist, kannst nur Du wissen, da Du Deinen Code nicht zeigst. Wie hast Du die Tabelle erzeugt?
Benutzeravatar
pixewakb
User
Beiträge: 1408
Registriert: Sonntag 24. April 2011, 19:43

Mal Pseudo-Code, dass man verstehen kann, warum ich die Abfrage mache:

Code: Alles auswählen

if (2018, 334) in [liste der (news_id-text_id)-Paare]:
    pass
else:
    download()
Das obige brauche ich, d. h. ich muss prüfen, ob ich die Seite schon habe, wenn ich sie nicht habe, muss ich sie runterladen.

Ich habe Schwierigkeiten da mehr Quellcode zu posten. Das ist (1) ein package mit vielen Modulen und (2) würde der Quellcode relativ leicht Rückschlüsse zulassen, was ich wo mache. Ich bitte um Verständnis.

Die Tabelle enthält "alles", d. h. ich habe nur eine Tabelle angelegt und im Kern die Spalten news_id, text_id, dann Überschrift, Untertitel, Text der Seite, einige Metadaten der Seite, URL der Seite usw. enthält.

Bitte hilf mir mal auf die Sprünge: Ich hatte vermutet, dass ich aus der ganzen Tabelle nur die beiden Spalten auslese und in eine Liste kippe. Ich brauche genau diese Liste.

a.) Kann ich das effizienter lösen mit einer Abfrage gegen die Datenbank?

b.) Ich hatte mal überlegt diese Paare in eine Textdatei zu packen und dort zu aktualisieren. Könnte das performanter sein?

Das ist für mich ein interessanter Nebenschauplatz und das erste Mal, dass ich mal mit einer Datenbank gearbeitet habe. Falls möglich würde ich es aber dennoch gerne fixen.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@pixewakb: Du machst Dir einen Index auf news_id und text_id und fragst die Datenbank direkt, so macht man das mit Datenbanken. Zum Prüfen in Python wäre ein set besser, und da ist das sortieren unsinnig.
Antworten