mmofacts.com

Freien Index finden

gepostet vor 18 Jahre, 10 Monate von BjoernLilleike
Gibt es in MySQL eine gute Möglichkeit den ersten nicht vorhandenen Wert zu finden?
Also in einer Tabelle mit 1, 2, 4,5 -> 3
gepostet vor 18 Jahre, 10 Monate von BjoernLilleike
Nagut, danke.
Aber leider ist keine Lösung dabei, die mir zusagt (einfach alles durchgucken, da wäre ich wohl auch noch drauf gekommen).

Ich suchte sowas wie SELECT * WHERE NOT IN USE id; oder so in der Art halt. Naja, denk ich mir halt was anderes aus.
gepostet vor 18 Jahre, 10 Monate von Klaus
ja sowas habe ich auch gesucht. Irgendwann ist mir dann etwas wie "INSERT INTO ... key=1 ON KEY EXISTS key=key+1" in den Sinn gekommen. Das soll den Sinn haben das MySQL, wenn es den key "1" gibt, den nächst höheren gibt usw.
Aber ich weiß nicht ob ich mir das nur eingebildet habe oder irgendwo gelesen und nicht mehr gefunden habe. Zuviel Chaos in meinem Kopf.
gepostet vor 18 Jahre, 10 Monate von KEEN
So kannst dus machen:

$i = 0;

$ergebnis = mysql_query("SELECT id FROM tabelle ORDER BY id");
while($row = mysql_fetch_array($ergebnis))
{
If($i+1 < $row['id']){$deine_lueckenzahl = $i+1;}
$i = $row['id']
}
gepostet vor 18 Jahre, 10 Monate von HSINC
das ist aber nicht wirklich sicher, weil indessen könnte die id ja schon wieder vergeben sein. und einen lock über die ganze tabelle zu legen ist eventuell perfmässig unschoen.
insofern ist die fragen warum man das machen sollte und ob man das nicht duch anderes db design umgehen kann
gepostet vor 18 Jahre, 10 Monate von BjoernLilleike
Ich brauche einen eindeutigen Wert zwischen 22000 und 55000 (oder äquivalent zwischen 1 und 33000) - wichtig ist, dass der jeweilige Wert nicht überschritten wird. Aber was in dem Beispiel von 1-5 noch praktikabel ist, wird so natürlich unsinnig, von den Bedenken wegen möglicher paralleler Änderungen mal ganz abgesehen.

Also konzentriere ich mich auf einen neuen Lösungsweg, der mit Unique Key arbeitet und LAST_INSERT_ID() nutzt. Soweit so gut.
Jetzt muss ich nur sicher stellen, dass der Autoinc-Key nicht über meinen Wert steigt.
Ich bin sicher, das insgesamt nie mehr als diese 30000 Einträge vorhanden sind, aber ich habe noch keinen Weg gefunden, die ID entsprechend zu beschränken.

Alternativ lege ich mir halt meine eigene Indextabelle an, in der alle zulässigen Zahlen als key und eine zweite Spalte mit null vorbereitet werden und ich nur noch auf den ersten Index suche, wo noch null steht und ich ansonsten meinen Wert eintrage.
Das ist zwar etwas mehr Speicherbedarf, aber dafür sollte es dann recht flott gehen.
gepostet vor 18 Jahre, 10 Monate von schokofreak
Björn: Solche Sachen kann man auf 2 Wege lösen:
- Man bildet einen Hash, kriegt den Wert somit in Nullzeit
- Man bildet komplexe Queries. Mit viel SQL Wissen schafft man es, hier ne Query zu bauen, welche ev. sogar über Indexe funktioniert. Nur bis man die hat... bis man die auf ne andere DB portiert...

Wie gesagt: Die Query variante ist meist n Performance- und Pflege Problem. Deshalb: Nimm dir n Hash.

Du weist, was es alles für werte geben kann?
Dann mach dir ne Zusatz-Tabelle, in welcher via Boolean gespeichert wird, ob schon in Einsatz?

Dann ist es n simples select where false, order by... maximum 1 record.

Gruss
gepostet vor 18 Jahre, 10 Monate von BjoernLilleike
Ja, so hatte ich mir das ja dann auch vorgestellt.
Nur dass ich möglichst direkt Updaten wollte, denn der Index soll dann ja auch besetzt sein.
Da ich da gleich zwei solcher Problemfälle drin unterkriege, schmerzt es mich der Speicherbedarf auch nicht allzusehr.
gepostet vor 18 Jahre, 10 Monate von Thomblin
such doch mit dem verfahren von keen nach einer zahl, ich würde da aber noch ein break einbauen falls du eine zahl gefunden hast, denn weitersuchen ist sinnlos, du brauchst ja nur eine lücke

dann versuchst du diese lücke zu füllen (mit update insert wie auch immer)
wenn das nicht geht, weil die zahl inzwischen schon benutzt wird suchst du einfach weiter (kannste ja in der selben schleife machen, also dann vlt vor dem break) und das so lange bis es funktioniert hat

also

über alle zahlen {
lücke gefunden {
wenn lücke noch vorhanden {
break;
}
}
}
gepostet vor 18 Jahre, 10 Monate von TheUndeadable
mysql> SELECT * FROM zahlen;
+------+
| zahl |
+------+
| 1 |
| 2 |
| 3 |
| 4 |
| 6 |
| 7 |
| 8 |
+------+
mysql> SELECT zahl + 1 FROM zahlen WHERE zahl NOT IN ( SELECT zahl - 1 FROM zahl
en) ORDER BY zahl LIMIT 1;
+----------+
| zahl + 1 |
+----------+
| 5 |
+----------+
gepostet vor 18 Jahre, 10 Monate von Chojin
Ich möchte hier nur kurz zwischenfragen, ob es wirklich sinn macht User-IDs lückenfrei zu halten. (dreht sich das topic überhaupt darum?)

Ich finde eine User-ID muss möglichst eindeutig sein und wenn ein account einmal gesperrt, gelöscht oder expired wurde, sollte kein anderer Account an dessen stelle tretten. :roll:

reg4rds
chojin
gepostet vor 18 Jahre, 10 Monate von schokofreak
Original von Chojin
Ich möchte hier nur kurz zwischenfragen, ob es wirklich sinn macht User-IDs lückenfrei zu halten. (dreht sich das topic überhaupt darum?)


Hat zwei sehr grosse Vorteile:
- Dadurch kann ein banales Constraint verhindern, dass ungewohlt zu viele User / Session aktiv sind. Da brauchts null verletzbare Programmlogik, die das überwacht.
-> Wie oft sieht man in nem OGame ne Auflistung von 10001 / 10000 Accounts reserviert?

- Dadurch wird man wirklich gezwungen, überall schön zu coden. Sprich ein User Drop muss wirklich alles entfernen, die Berechtigungen müssen wirklich überall sauber abgefangen werden.

Wenn man dann noch die versteckteren Vorteile ankuckt:
- Man weiss von Beginn weg, wie viele User es geben wird. Kann somit (brutal gesagt) im SHM n Array anlegen, dieses ist banal adressierbar und Spiechert Informationen zu einem user.

Das selbe geht natürlich auch über n Datenfile... Caching wird umständlich, wenn die Gesamtmenge der Datensätze nicht bekannt ist / die ID's nicht gleichzeitig als SpeicherplatzNummer verwendet werden können.

Gruss
gepostet vor 18 Jahre, 10 Monate von mifritscher
Die Anzahl der Datenstätze bekommt man auch über SELECT count(*) FROM tabelle...

Ich finde auch, das eine einmal belegte ID nicht wieder verwendet werden sollte. Wenn du nicht bei jeder Nachricht den Namen des Senders mit speicherts, kann es sonst passieren, dass es plözlich ovn jemanden anderen geschrieben scheint, Anwortbuttons sind viel aufwendiger etc. etc.

Wenn du unbedingt die IDs für Cachingzwecke fortlaufend brauchst mache doch einfach beim Auslesen an Stelle von gelöschten IDs BlindUser rein
gepostet vor 18 Jahre, 10 Monate von schokofreak
Naja...
N select muss man ausführen; n Constraint nicht

Wenn ein User gelöscht wird, so werden auch all seine gesendeten MItteilungen gelöscht.
Respektive deren ID ev. auf -1 gesteckt; Droped User.

Alles andere ist wie gesagt ein nicht sauberes DB design und sowas zwingt zu sauberem DB Design.

Gruss
gepostet vor 18 Jahre, 10 Monate von Chojin
Original von schokofreak

Alles andere ist wie gesagt ein nicht sauberes DB design und sowas zwingt zu sauberem DB Design.


Tut mir leid schoko, aber eine ID wiederzuverwenden wiederspricht sich mit allem was ich jemals von sauberem DB Design gehört habe.

Die alten Nachrichten zu löschen hat etwas mit Datenbankpflege und nicht mit deren Design zu tun und sollte selbstverständlich sein.

Das ist also völlig unabhängig davon, ob die ID fortlaufend lückenlos ist oder nicht und damit auch keine Rechtfertigung. :roll:

Die Anzahl der Spieler kann immer mit SELECT count(id) FROM user WHERE status = 1 rausfinden und läuft deutlich schneller als die Suche nach einer freien ID, beispielsweise wenn sich jemand neu anmelden will und geprüft werden muss ob es noch platz gibt.

reg4rds
chojin
gepostet vor 18 Jahre, 10 Monate von Kampfhoernchen
Ich stimme Chojin da zu.

Ich würde sogar noch einen Schritt weiter gehen, und überhaupt keine DELETES ansetzen, sondern ein weiteres Datenfeld "status" hinzufügen, in dem gespeichert wurde, ob der entsprechende Datensatz gelöscht wurde. Mit einem View mit dem Anhängsel "WHERE status=true" ändert sich für den Code dabei überhaupt nichts.
gepostet vor 18 Jahre, 10 Monate von Fornax
So hatte ich das mal, aber ich habe mir gedacht, dass wenn ich mehr Spieler bekommen das zuviel Speicherplatz braucht. Stell dir mal vor, du hast 100 Aktive und 200 gelöschte Benutzer. Dann hat man 200% unnötigen Speicherplatzverbrauch :roll:
gepostet vor 18 Jahre, 10 Monate von schokofreak
Also: Wenn ein User entfernt wird. Dann heist:
Dass sämtliche Messages des Betreffenden Users gelöscht werden müssen. Wieso? Weil im From n FK auf den nun entfernten User vorhanden ist.

Genauer gesagt heist das, dass sämtliche User-Bezogenen Informationen gelöscht werden müssen. Wird dies nicht getan, macht man sich sowohl Probleme mit Datenschutz udn auch Sicherhietsprobleme.

Wenn nun n User gelöscht wurde; sämtliche FKs in der Konsequenz dessen ebenfalls zur Löschung führten. Dann kann eine DB ID Jederzeit wiederverwendet werden.

Und n Count SQL usw. Überleg mal: Willst du n User hinzufügen, muss dein PHP zuerst n Count machen; danach den User erstellen.
-> Was wenn nun der User nicht über das PHP erstellt wird; du probleme mit Transaktionen hast oder schlampig programmierst?

Wenn du Constraint hast... da machst n Neuen User: Sprich select nach tiefster ID, diese hinzufügen. Entweder gibet die nun schon -> Exception oder sie verletzt das Constraint -> Exception.
Will soviel heissen: Das PHP kann noch so dof sein, noch so viele Fehler tolerieren oder nicht Transaktionstauglich sein... who cares?
Und mal davon abgesehen dass auch jedes andere Tool auch keine zusätzlichen user erstellen kann (also niht über PHP connect).

Somit kanst du im PHP noch so viele Bugs und Sicherheitslecks haben; Es geht einfach nciht mehr.
DAS ist der grosse Unterschied.

Sicherheit bedeutet dass man alles immer löscht. Keine DB Weisen mehr vorhanden sidn.
Sicherheit bedeutet auch, dass man so viel wie möglich so tief wie möglich validiert. Speziell bei Sessions ist dies wichtig dass man es nach möglichkeit in der DB tut.

Gruss
gepostet vor 18 Jahre, 10 Monate von schokofreak
Original von Kampfhoernchen
Ich würde sogar noch einen Schritt weiter gehen, und überhaupt keine DELETES ansetzen, sondern ein weiteres Datenfeld "status" hinzufügen, in dem gespeichert wurde, ob der entsprechende Datensatz gelöscht wurde. Mit einem View mit dem Anhängsel "WHERE status=true" ändert sich für den Code dabei überhaupt nichts.


Das ist bei Personenbezogenen Daten, da zähl ich sowohl Login als auch E-Mail dazu, illegal.
gepostet vor 18 Jahre, 10 Monate von BjoernLilleike
Da habe ich nicht den Eindruck, dass sich viele daran halten.
Wie oft habe ich schon Mail für ein Spiel erhalten, dessen Account ich schon vor Monaten explizit gelöscht hatte..
gepostet vor 18 Jahre, 10 Monate von schokofreak
Original von BjoernLilleike
Da habe ich nicht den Eindruck, dass sich viele daran halten.
Wie oft habe ich schon Mail für ein Spiel erhalten, dessen Account ich schon vor Monaten explizit gelöscht hatte..


Hab auch schon oft gegen Einheiten gekämpft, deren Spieler längst gelöscht wurde Das ist irgendwie n problem der BG Progger... dürfte wohl daran liegen dass man bei MySQL der alten Versionen nicht so einfach mal rasch eben alles Spielerbezogene löschen kann.

Gruss
gepostet vor 18 Jahre, 10 Monate von Klaus
oder jemand postet in einem Forum einen Link zu einem Profil eines Spielers, der später gelöscht wird. Damit erreichst du nur eine allgemeine Verwirrung wenn diese ID dann anders besetzt wird.
gepostet vor 18 Jahre, 10 Monate von Fornax
Dann kann man ja mit der URL die E-Mail (Nick oä) und nicht die ID übergeben...
gepostet vor 18 Jahre, 10 Monate von Chojin
Mensch schoki,
das ist mal grober dummfug den du da schreibst.

Original von schokofreak

Das ist bei Personenbezogenen Daten, da zähl ich sowohl Login als auch E-Mail dazu, illegal.

Klar musst du dem User die Möglichkeit bieten seine Daten zu löschen, oder du machst das für ihn, deshalb darf trotzdem der Datensatz bestehen bleiben, obendrein sind allenfalls Personenbezogene Daten zu löschen und ein frei wählbarer Loginname zählt da sicher nicht dazu.
Obendrein behalt ich mir vor für eine gewisse Zeit gelöschte Accounts als Farmbare Ruinen für die aktiven im Spiel zu behalten.

Original von schokofreak

Also: Wenn ein User entfernt wird. Dann heist:
Dass sämtliche Messages des Betreffenden Users gelöscht werden müssen. Wieso? Weil im From n FK auf den nun entfernten User vorhanden ist.
Nochmal: Die Nachrichten sollte man sicher löschen, hat aber nix mit der User-Tabelle zu tun.

Original von schokofreak

Genauer gesagt heist das, dass sämtliche User-Bezogenen Informationen gelöscht werden müssen. Wird dies nicht getan, macht man sich sowohl Probleme mit Datenschutz udn auch Sicherhietsprobleme.
Warum?
Datenschutz bezieht sich nur auf schützenswerte Informationen und die kann man entfernen oder den user editieren lassen.
Sicherheitsprobleme entstehen durch abgelaufene Userdaten jedenfalls nicht automatisch. (wenn der programmierer nicht auf den kopf gefallen ist)

Original von schokofreak

Und n Count SQL usw. Überleg mal: Willst du n User hinzufügen, muss dein PHP zuerst n Count machen; danach den User erstellen.
-> Was wenn nun der User nicht über das PHP erstellt wird; du probleme mit Transaktionen hast oder schlampig programmierst?
Also ich hab nicht den Vorsatz mein Spiel schlampig zu programmieren, deshalb versteh ich dein Argument nicht wirklich...
Ich denke ein COUNT läuft deutlich schneller als dein "Check_for_free_ID" prozess.

Original von schokofreak

Wenn du Constraint hast... da machst n Neuen User: Sprich select nach tiefster ID, diese hinzufügen. Entweder gibet die nun schon -> Exception oder sie verletzt das Constraint -> Exception.
Will soviel heissen: Das PHP kann noch so dof sein, noch so viele Fehler tolerieren oder nicht Transaktionstauglich sein... who cares?
Und mal davon abgesehen dass auch jedes andere Tool auch keine zusätzlichen user erstellen kann (also niht über PHP connect).
Wenn du in der User-Tabelle das Feld ID als Index mit autoincrement verwendest, kannst du auch per hand user anlegen und bekommst automatisch ne freie (weil neue) nummer.

Original von schokofreak

Somit kanst du im PHP noch so viele Bugs und Sicherheitslecks haben; Es geht einfach nciht mehr.
DAS ist der grosse Unterschied.
Du vermischt Programmiergrundsätze und Buzwords um dein Vorgehen zu rechtfertigen, wobei deine Art das Problem zu lösen in meinen Augen mehr Aufwand als Nutzen bringt und das System weithin unflexiebler macht.

Reg4rds
chojin
gepostet vor 18 Jahre, 10 Monate von BjoernLilleike
Ich möchte an dieser Stelle nochmal anmerken, dass es bei meinem ursprünglichen Problem keinesfalls um irgendwelche UserID ging, sondern um schnell veränderliche temporäre Daten, bei denen ich aus Speichergründen nunmal nicht mehr Feldgröße vorhalten möchte als gebraucht wird, weil es sich innerhalb kurzer Zeit auf etliche MB aufsummieren würde.

Ich kann aber auch nicht einfach einen Autowert der Datenbank nehmen, weil in dem maximalen Wertebereich des verwendeten smallInt eben auch andere Daten liegen.
Und ja, ich habe diese Lösung nach Abwägen aller Möglichkeiten mit Bedacht gewählt.

Also schlagt euch bitte nicht die Köpfe ein um UserID, die man sicher nach eigenen Vorstellungen so oder so handeln kann.
gepostet vor 18 Jahre, 10 Monate von Chojin
Also wenn das ganze schnell sein muss und nur eine begrenzte anzahl an MB hat, dann mach doch ne HEAP-Table draus. Da sind Operationen wie UPDATE, INSERT und DELETE wirklich in einem Bruchteil normaler Zugriffszeit abgearbeitet.
Trotzdem würde ich alte/abgearbeitete Datensätze löschen und neue mit einer neuen ID versehen. Das ist sehrviel Performanter als lange nach einem freien Platz zu suchen.

reg4rds
chojin
gepostet vor 18 Jahre, 10 Monate von BjoernLilleike
Zu dieser Lösung meines Problems sind wir ungefähr Ende Seite 1 dieser Diskussion gekommen

Auf diese Diskussion antworten