Seite 1 von 3

Kleines Verständnisproblem!

Verfasst: 29.05.2007 10:03
von PureBasic4.0
Hi, Leute

Ich habe hier den folgenden Code (der mit Sicherheit falsch ist):

Code: Alles auswählen

          SqlString$ = "SELECT ID FROM Shortcuts"
          SQLiteGetTable(DBHandle,SqlString$,Table)
          If Table
            SQLiteNextCol(DBHandle)
            While SQLiteNextRow(DBHandle)
              Ergebnis$ = SQLiteValue(Table)
              AddElement(Verknuepfungszahlen())
              Verknuepfungszahlen() = Val(Ergebnis$)
            Wend
            ResetList(Verknuepfungszahlen())
            ok = 0
            Anzahl = 0
            Repeat
              Anzahl + 1
              ForEach Verknuepfungszahlen()
                If Anzahl <> Verknuepfungszahlen()
                  ok = 1
                EndIf
              Next
            Until ok = 1
          EndIf
Ich möchte alle IDs aus der DB auslesen und eine freie finden. Das mache ich, indem ich alle IDs in eine LinkedList schreibe und versuche, alles mit der einen Zahl (Variable Anzahl) zu vergleichen. Leider ist mir das Codemäßig nicht wirklich gelungen. Habt ihr vielleicht einen besseren Code?

Des Weiteren ist der Code wirklich langsam. Das Auslesen aller IDs dauert bei einer leeren Datenbank ca. 5 Sek. Ich denke, dass kann man Performancemaßig auch noch aufpolieren, oder?

BITTE HELFT MIR!

Danke,

PureBasic4.0

Verfasst: 29.05.2007 10:25
von Kaeru Gaman
wie groß ist denn der zahlenraum der IDs?
wenn der überschaubar ist (z.b. 0 - 65536) könntest du ein array mit der ID als Index zum "mitschreiben" benutzen.

Code: Alles auswählen

Dim Liste.b(65535)
;...
    SQLiteNextCol(DBHandle)
    While SQLiteNextRow(DBHandle)
      Ergebnis$ = SQLiteValue(Table)
      Verknuepfungszahl = Val(Ergebnis$)
      Liste(Verknuepfungszahl) = 1
    Wend 

  TestCount = 0
  While Liste(TestCount)  And TestCount < 65536
      TestCount +1
  Wend

Verfasst: 29.05.2007 10:27
von PureBasic4.0
Hi, Kaeru

Die Anzahl sollte sich schon dynamisch entfalten können. Ich möchte daher auch eher bei LinkedLists bleiben (um einen Buffer Overflow zu vermeiden).

Ich habe zurzeit eher Probleme mit der Überprüfung, ob es eine bestimmte ID bereits gibt. Ich glaube, da sind etliche Fehler drin

Verfasst: 29.05.2007 10:43
von Kaeru Gaman
> um einen Buffer Overflow zu vermeiden
:? hu?
das versteh ich nicht...

> Die Anzahl sollte sich schon dynamisch entfalten können.
kann sie ja auch.
das Array ist auch nicht dafür da, irgendetwas zu zählen,
nur die vergebenen IDs zu notieren.
der klare vorteil dabei ist:
du gehst die "notizenliste" und gleichzeitig die zahlenschleife nur ein einziges mal durch.
bei einer LL lösung musst du ja die zahlenschleife durchgehen,
und jede einzelne zahl mit allen listenelementen vergleichen.

falls du dir sorgen um deinen speicherbereich machst,
das Array oben braucht nur 64K des hauptspeichers,
und du hast damit für die IDs einen Zahlenraum von 65536.
du kannst also mit einem 1MB großen Array einen zahlenraum von 1048576 verwalten.
das genügt für eine 6-stellige ID 0-999999 ... ;)

man kann das ganze noch verschlanken:
du brauchst ja eigentlich nur ein einziges Bit als flag,
also könntest du in dem byte eines Arrayfeldes ganze 8 flags halten.

Code: Alles auswählen

Dim Liste.b(65535)
;...
    SQLiteNextCol(DBHandle)
    While SQLiteNextRow(DBHandle)
      Ergebnis$ = SQLiteValue(Table)
      Verknuepfungsbyte = Val(Ergebnis$)
      Verknuepfungsbit = Verknuepfungsbyte & 7  ; Modulo 8
      Verknuepfungsbyte / 8
      Liste(Verknuepfungsbyte) | (1 << Verknuepfungsbit) ; Bit setzen
    Wend 

  TestByte = 0
  While Liste(TestByte) = 255 And TestCount < 65536
    TestByte +1
  Wend
  TestBit = 0
  While Liste(TestByte) & (1 << TestBit)
    TestBit +1
  Wend
  FoundID = 8* TestByte + TestBit
hier genügen die 64K jetzt für einen zahlenraum von 524288.

deine lösung wäre mir einfach zu langsam.
außerdem sparst du auch nicht SO viel speicherplatz, weil du 12byte für jedes listenelement benötigst.
d.h., sobald du mehr als 5461 datensätze hast, wird deine liste auch größer als 64K.

...aber ich schau mir deinen logigfehler trotzdem mal an...

[edit] so, hab ich..
so müsste es laufen....

Code: Alles auswählen

TestCount = #LowestPossibleID -1
Repeat
  TestCount + 1
  ok = 1
  ForEach Verknuepfungszahlen()
    If TestCount = Verknuepfungszahlen()
      ok = 0 : Break
    EndIf
  Next
Until ok = 1

Verfasst: 29.05.2007 12:10
von PureBasic4.0
@Kaeru: Danke, habe deinen letzten Code übernommen. Allerdings habe ich folgendes Problem: Die LinkedList wird riesig!!! (3370620), obwohl in der Datenbank überhaupt keine (0) vorhanden sind. Hier ein Screenshot:

Bild

Wie kann man das verbessern?

Re: Kleines Verständnisproblem!

Verfasst: 29.05.2007 12:17
von Kiffi
PureBasic4.0 hat geschrieben:

Code: Alles auswählen

If Table 
  SQLiteNextCol(DBHandle)
  While SQLiteNextRow(DBHandle)

Code: Alles auswählen

If Table 
  SQLiteNextCol(Table)
  While SQLiteNextRow(Table)
Grüße ... Kiffi

Verfasst: 29.05.2007 13:13
von Thorsten1867
Zur Beschleunigung solltest du zu Beginn "BEGIN TRANSACTION;"
und zum Schluss "COMMIT;" mit SQLiteExecute() ausführen.

Verfasst: 29.05.2007 13:19
von PureBasic4.0
@Kiffi: Danke!

@Thorsten1867: Ich denke, Transactions kann ich später mal einfügen. Es geht jetzt nach dem Bugfix von Kiffi schon ziemlich schnell.


@all: Hier ist der verbesserte Code:

Code: Alles auswählen

          SqlString$ = "SELECT ID FROM Shortcuts"
          SQLiteGetTable(DBHandle,SqlString$,Table)
          If Table
            SQLiteNextCol(Table)
            While SQLiteNextRow(Table)
              Ergebnis$ = SQLiteValue(Table)
              AddElement(Verknuepfungszahlen())
              Verknuepfungszahlen() = Val(Ergebnis$)
            Wend
            ResetList(Verknuepfungszahlen())
            ok = 0
            Anzahl = -1
            Repeat
              Anzahl + 1
              ok = 1
              ForEach Verknuepfungszahlen()
                If Anzahl = Verknuepfungszahlen()
                  ok = 0
                  Break
                EndIf
              Next
            Until ok = 1
            Debug Anzahl
Funktioniert soweit alles. Danke an alle! :mrgreen:

Verfasst: 29.05.2007 13:41
von Kiffi
@Thorsten1867:

Transaktionen bringen nur was, wenn man Daten schreibt. ;-)

Grüße ... Kiffi

Verfasst: 29.05.2007 14:12
von Thorsten1867
Kiffi hat geschrieben:@Thorsten1867:

Transaktionen bringen nur was, wenn man Daten schreibt. ;-)

Grüße ... Kiffi
Dann aber eine Menge! :D