| 

.NET C# Java Javascript Exception

4
Hi Alle,
es geht um eine einfache Tabelle im Microsoft SQL Server (2008 R2 Standard), mit wenigen Spalten. Eine davon speichert vollständige URLs, die bis zu 1000 Zeichen lang sein können. Und bei dieser Länge unterstützt der MS SQL Server meines Wissens nicht, dass diese Spalte indiziert werden kann (max 400 Zeichen). Bei jedem Speichervorgang muss ich jedoch suchen, ob es diese URL schon gibt - und dann suche ich durch die ganze Tabelle, ohne Index. Aktuell sind 250.000 Zeilen drin, und langsam geht der Server bei parallelen Zugriffen in die Knie. Hat jemand eine Idee, wie man das lösen kann?
Danke und Grüße, Marc

PS: Entwicklungsumgebung .NET4, VB, VS2010
01.03.2011
marc2000 75 4
5 Antworten
4
Hi Marc,

schau mal hier: MD5 - Hash eindeutig?
Ich glaube, dass die Wahrscheinlichkeit, dass Du innerhalb deines Systems auf einen doppelten Hashwert kommst sehr, sehr gering ist. Die Möglichkeit ist natürlich prinzipiell vorhanden.

Das Umrechnen bedarf sicherlich etwas Zeit, aber dafür spart man das Vielfache an Zeit bei der Abfrage der Datenbank ein. Ob das Ganze für Dein Programm taugt musst Du einfach mal testen.

Hier mal noch eine Funktion die einen MD5-String zurückgibt:

Imports System.Security.Cryptography
Imports System.Text

Public Function GenerateMD5String(ByVal url As String) As String
Dim md5Bytes As Byte()
Dim encoder As New UTF8Encoding()
Dim md5Hasher As New MD5CryptoServiceProvider()
md5Bytes = md5Hasher.ComputeHash(encoder.GetBytes(url))

Dim returnString As String = Nothing
For Each bt As Byte In md5Bytes
returnString &= bt.ToString("x2")
Next

Return returnString
End Function
01.03.2011
SensenMannLE 1,2k 1 8
Ich habe die Funktion nochmal editiert, da ist mir eine doppelte Zeile reingerutscht.
SensenMannLE 01.03.2011
Danke sehr für das Snippet. Ich probiers gleich mal aus. Den Hinweisen zufolge sollte die Eindeutigkeit für meine Zwecke ausreichen, sollte in hundert Jahren mal ein Fehler im Index sein, ist der zu verschmerzen.
marc2000 01.03.2011
2
Ein Vorschlag, der vll. nicht der beste ist, aber durchaus funktionieren könnte wäre, aus der URL die Du speicherst einen MD5-Wert zu generieren und über diesen zu indizieren. Den könnte man dann sogar als Primärschlüssel für die Tabelle verwenden.

Allerdings nur, wenn wirklich nur eindeutige URL's gesperichert werden.
01.03.2011
SensenMannLE 1,2k 1 8
Sorry, ich habe eine neue Antwort aufgemacht statt hier zu kommentieren...
marc2000 01.03.2011
1
Ergebnis:
Der Test mit dem Snippet von Sensenmann ist abgeschlossen. Der Code funktioniert einwandfrei.
Das Erstellen von 200.000 Hashwerten für URLs (nvarchar 1000) dauerte ohne Parallelisierung keine drei Minuten (wobei das lesen und schreiben vom SQL vermutlich die meiste Zeit kostet).
Der Engpass auf dem Server ist verschwunden - von 8 Core Volllast bis zur Grätsche (Timeout) ist jetzt nichts mehr da, der Server idlet beim gleichen Prozess um die 3% Last. Der Client, der jetzt bei jeder Anfrage nicht mehr nur eine URL an den Server schickt, sondern vorher noch den Hash berechnen muss, ist etwa 25% langsamer.
Vielen Dank, mein Problem ist gelöst.
03.03.2011
marc2000 75 4
0
Hi,

Müsstest Du auf das Feld nicht ein Full Text Index legen können?

Kleiner Hinweis:
Bei der Abfrage auf ein indiziertes VARCHAR Feld mit
LIKE '%ABC'
wird der
Index ignoriert.
Bei dem Aufruf von
LIKE 'ABC%'
wird er benutzt.
01.03.2011
KHoffmann 939 6
Hi KHoffmann, ich habe keine Erfahrung mit dem Volltextindex. Ich frage nie einen Teil des Feldes ab, sondern immer den ganzen Feldinhalt. Dein Hinweis mit LIKE ist richtig aber hilft in meinem Fall leider nicht. Bringt der FullTextIndex auch etwas bei Suche nach vollem Feldinhalt?
marc2000 01.03.2011
0
Hallo Sensenmann,
das mit dem Hashwert klingt ja sehr verführerisch. Wenn ich angenommen 10.000 URLs in Hashwerte umrechnen will, massiv parallel auf einer schnellen 8 Prozessormaschine - hast Du eine Idee, wie schnell das geht? Ist eine blöde Frage, ich weiss, hängt von vielem ab, aber nur fürs Gefühl.
Und noch was - ich kenn mich mit MD5 nicht gut aus, aber ich habe eben gelesen, dass man zwei Texte erstellen kann, die die gleiche MD5 auswerfen. Ist das dann ein sicheres Verfahren, die MD5 als Primärschlüssel zu verwenden? Wie hoch ist die Wahrscheinlichkeit, dass zwei unterschiedliche URLS den gleichen Hash haben?
Danke jedenfalls schonmal für die super Idee.
Marc
01.03.2011
marc2000 75 4
2
Hallo Marc, ich beantworte mal deine Frage. Selbst ohne mehrere Threads sollten 10.000 URLs sich in wenigen Stunden umwandeln lassen. Mit mehreren Threads wirst du wohl in etwa einer Stunde (geschätzt) fertig sein. Die Kollisionswahrscheinlichkeit beträgt 32^36 (1.5324955408658889e+5).
Floyd 01.03.2011
2
Floyd hat die Zahl schon genannt. Hier ist auch eine Diskussion dazu: http://stackoverflow.com/questions/2444321/how-are-hash-functions-like-md5-unique
Hier ein Zitat:
'But hashes are not about "unique", they are about "unique enough".'
Jürgen Luhr 01.03.2011
Unique enough müsste für meine Zwecke reichen. Ich lese mal den link nach. Danke für die Zahlen. Zunächst hat mich die Einschätzung in der MSDN irritiert (http://msdn.microsoft.com/de-de/library/system.object.gethashcode.aspx), MS selbst sagt hier zumindest bei der Implementierung von GetHashCode, das sei für einen Index nicht geeignet. Weiss jemand die beste Methode/Klasse, um Hashwerte in .NET zu berechnen?
marc2000 01.03.2011
1
Eine kleine Korrektur zu der Schätzung bezüglich der benötigten Zeit um für 10.000 URLs die MD5-Hashes zu berechnen. Hab mit einem Kollegen gesprochen der sich mit der Materie gut auskennt und er meinte, das die benötigte Zeit im Sekundenbereich, maximal jedoch im Minutenbereich liegt (je nachdem wie gut die Implementierung im .Net-Framework ist). Meine Schätzung mit Stunden ist also weit überzogen.
Floyd 02.03.2011
OK, das hatte ich gehofft. Hatte Deine Antwort mal als "Pending Risk" eingestuft, werde das heute am Patient selbst ausprobieren und geb das Ergebnis dann hier bekannt. Sehr beruhigend, danke für Deinen Kommentar!
marc2000 02.03.2011

Stelle deine Sql-Frage jetzt!