Anzeige - [Hier werben / Mediadaten]
(?) Tags raten (?) sql race umkreissuche (edit)
 
Reply to this topicStart new topicStart Poll
> SQL Hardcore: Race-Condition bei der Umkreissuche
jAuer
Jürgen Auer - freiberufl. Programmierer
Geschrieben am: Di 29.07.2008, 14:01
Report PostQuote Post

AyomRank 9
Group Icon

Gruppe: Experten Entwicklung
Beiträge: 2432
Mitglied seit: 4.02.2006


Seit über einem Jahr laufen auf server-daten Kundendatenbanken mit implementierter Umkreissuche und der OpenGeoDb im Hintergrund, um Nutzereingaben (Ort, PLZ) Geokoordinaten für die Suche zuzuordnen.

Heute früh schickte mir das System eine Mail:

CODE
A domain error occurred. (SqlError 3623, Class 16)


Bei der Umkreissuche auf einer Kundendomain hatte jemand eine existierende PLZ eingegeben, zu dieser gab es eine Fundstelle - und die obige Fehlermeldung, der Nutzer sah diese nicht.

Der (automatisch generierte) Code ist sehr komplex: Eine gespeicherte Prozedur ruft eine Funktion auf, die eine temporäre Tabelle mit IDs zurückgibt (Filterung plus Sortierung), an diese Tabelle werden per Join die eigentlichen Daten angehängt. U.a. wird eine Spalte mit der Distanz zur Eingabe des Nutzers ausgegeben:

CODE
(ACos((SIN(A.latitude_r) * SIN(@i_latitude_r)) +
   (COS(A.latitude_r) * COS(@i_latitude_r) * COS(@i_longitude_r - A.longitude_r))
   ) * 6378.137) As Distance


Das ist die allgemeine Formel zur Berechnung der Entfernung zwischen Eingabekoordinaten (hier: @i_latitude_r, @i_longitude_r im Bogenmaß) und Werten aus einer Tabelle (hier: A.latitude_r, A.longitude_r).

Der Filter- und Sortiercode in der Funktion enthält einen analogen Codeschnipsel, die Sortierung kann über verschiedenste Spalten gehen (per Case), ebenso können verschiedenste Filterkriterien (nach Nutzereingaben und / oder Entfernung) übergeben werden.

Einsicht nach längerem Rumsuchen:

(1) Klammere ich den obigen Code aus, funktioniert die Suche nach dieser PLZ. Obwohl derselbe Codeschnipsel dabei intern aufgerufen wird.
(2) Führe ich denselben Code direkt auf der Tabelle aus, dann funktioniert das über alle Datensätze.

Frage: Wo steckt der Fehler?

Hinweise: (1) Threadtitel, (2) die Fundstelle lag nahe an der Sucheingabe. Wohlgemerkt: Der Code ist in mehreren Kundendatenbanken teilweise seit über einem Jahr im Einsatz. Die Mailbenachrichtigung gibt es schon seit dem Start - dies war das erste Mal.


--------------------
Web-Anwendung 3.0: Ein Online-Kalender für Termine vieler Filialen.

server-daten - die Single-Data-Solution: Web-Datenbanken als Online - CRM - Lösung.
Ihre Geschäftsprozesse entscheiden, was Ihre Online-Datenbank macht. Sie konzentrieren sich auf Ihr Kerngeschäft - Ihre Datenbank funktioniert.
Top
PMEmail PosterUsers Website
Top
 
 
hatschi1810
#2 Geschrieben am: Di 29.07.2008, 15:26 (+01:25)
Report PostQuote Post

AyomRank 6
Group Icon

Gruppe: Experten Entwicklung (Mod)
Beiträge: 638
Mitglied seit: 20.01.2004


Die Formal haben wir so auch in Betrieb, hast du die Werte der Start-Endpunkte?
Falls ja wäre interessant ob du das Statement "händisch" laufen lassen kannst.

Du dürftest da aber nicht der einzige sein:
http://www.sitepoint.com/forums/showthread.php?t=400365
Top
PMEmail Poster
Top
 
Irene
irene.ch
#3 Geschrieben am: Di 29.07.2008, 16:38 (+01:12)
Report PostQuote Post

AyomRank 7
Group Icon

Gruppe: Experten Entwicklung (Mod)
Beiträge: 1114
Mitglied seit: 3.05.2004


Das ist mal eine Knacknuss ;-)

Von Trigonometrie versteh ich nichts. Da die Umkreissuche schon lange läuft, geh ich davon aus, dass die Formel stimmt. Die Fehlermeldung deutet aber auf ein Problem mit den Trigonometriefunktionen hin, weil der "domain error" genau dann kommt, wenn die Eingabewerte für diese Funktionen nicht im erlaubten Bereich liegen.

Der Hinweis auf die Race Condition lässt vermuten, dass es ein Problem mit der temporären Tabelle gibt. Falls die temporäre Tabelle irgendwie gespeichert wird oder die SQL-Connection zwischen verschiedenen Benutzerzugriffen geteilt wird, könnte es zu einem Daten-Durcheinander kommen.

Was es auch gibt, sind User die doppelt auf einen Submitbutton klicken. So würde die Umkreissuche dann innert Sekundenbruchteilen zweimal gestartet, und selbst wenn die SQL-Connection streng nach Usern getrennt ist, könnte es in diesem Fall zu Überschneidungen kommen.

Ich hoffe dass meine Vermutungen in die richtige Richtung gehen, obwohl ichs nicht selber ausprobieren kann.

Griessli
Irene


--------------------
Top
PMUsers Website
Top
 
jAuer
Jürgen Auer - freiberufl. Programmierer
#4 Geschrieben am: Di 29.07.2008, 17:26 (+00:48)
Report PostQuote Post

AyomRank 9
Group Icon

Gruppe: Experten Entwicklung
Beiträge: 2432
Mitglied seit: 4.02.2006


QUOTE (hatschi1810 @ Di 29.07.2008, 15:26)
Falls ja wäre interessant ob du das Statement "händisch" laufen lassen kannst.

Der 'händische Versuch' führte zu der (heute früh etwas entgeisterten) Beobachtung (2). Das lief nämlich anstandslos durch, generierte keinen Fehler und listete brav die Zeilen mit der Entfernung zum Startpunkt auf.

QUOTE (Irene @ Di 29.07.2008, 16:38)
Der Hinweis auf die Race Condition lässt vermuten, dass es ein Problem mit der temporären Tabelle gibt. Falls die temporäre Tabelle irgendwie gespeichert wird oder die SQL-Connection zwischen verschiedenen Benutzerzugriffen geteilt wird, könnte es zu einem Daten-Durcheinander kommen.

Was es auch gibt, sind User die doppelt auf einen Submitbutton klicken. So würde die Umkreissuche dann innert Sekundenbruchteilen zweimal gestartet, und selbst wenn die SQL-Connection streng nach Usern getrennt ist, könnte es in diesem Fall zu Überschneidungen kommen.


Zu einem 'Datendurcheinander' sollte es eigentlich nicht kommen, weil dann der ganze Sql-Server (MS-Sql2005 - Enterprise) ja etwas doof wäre. Die temporäre Tabelle stammt nicht manuell von mir, sondern wird implizit vom SqlServer genutzt, da ich eine Tabellenwertfunktion definiert und verwendet habe.

Also Code, der eine Tabelle zurückgibt. Da deklariert man eine Tabellenvariable, kann diese (verzweigt nach Sortierung aufwärts / abwärts, das läßt sich ansonsten nicht parametrisieren) mit Daten befüllen und gibt sie zurück. Es verwenden zwar verschiedene Nutzer (sogar verschiedene Kunden) dieselben Sql-Connections, weil der Webserver nur eine Anmeldekennung hat (würde man verschiedene Sql-Server-Nutzer deklarieren, dann würden tonnenweise verschiedene Ablaufpläne generiert werden, so nutzen viele Nutzer nur ganz wenige Pläne). Aber das sind keine von mir definierten 'Create Table #Tabellenname', die beim Aufrechterhalten der Verbindung weiterexistieren würden.

Nach dem Start dieses Threads (die Lösung weiß ich seit heute früh) fiel mir auf, daß die Variante (2) crasht, falls man den Datentyp von @i_latitude_r / @i_longitude_r von Decimal(18,8) auf Decimal(18,14) verbessert.


QUOTE (Irene @ Di 29.07.2008, 16:38)
Da die Umkreissuche schon lange läuft, geh ich davon aus, dass die Formel stimmt. Die Fehlermeldung deutet aber auf ein Problem mit den Trigonometriefunktionen hin, weil der "domain error" genau dann kommt, wenn die Eingabewerte für diese Funktionen nicht im erlaubten Bereich liegen.


Ersteres stimmt - und zweiteres lieferte schließlich den Gedanken zur Lösung.


--------------------
Web-Anwendung 3.0: Ein Online-Kalender für Termine vieler Filialen.

server-daten - die Single-Data-Solution: Web-Datenbanken als Online - CRM - Lösung.
Ihre Geschäftsprozesse entscheiden, was Ihre Online-Datenbank macht. Sie konzentrieren sich auf Ihr Kerngeschäft - Ihre Datenbank funktioniert.
Top
PMEmail PosterUsers Website
Top
 
jAuer
Jürgen Auer - freiberufl. Programmierer
#5 Geschrieben am: Di 29.07.2008, 17:38 (+00:12)
Report PostQuote Post

AyomRank 9
Group Icon

Gruppe: Experten Entwicklung
Beiträge: 2432
Mitglied seit: 4.02.2006


Kleiner Nachtrag:

CODE
Declare @i_latitude Decimal(18,8),
@i_longitude Decimal(18,8),
@i_latitude_r Decimal(18,8),
@i_longitude_r Decimal(18,8)

Set @i_latitude = 51.49027615464600
Set @i_longitude = 7.49839939608644
Select @i_latitude_r = Radians(@i_latitude), @i_longitude_r = Radians(@i_longitude)
Select A.AdressenId,
A.latitude, A.longitude,
A.latitude_r, A.longitude_r,
(ACos((SIN(A.latitude_r) * SIN(@i_latitude_r)) +
  (COS(A.latitude_r) * COS(@i_latitude_r) * COS(@i_longitude_r - A.longitude_r))
  ) * 6378.137) As Distance
From Adressen As A
Order By Distance


Daten der ersten Zeile:

CODE
155 51.49027615464600 7.49839939608644 0.89867485165970 0.13087175809126 0


Man sieht, das ist exakt dasselbe. Trotzdem sollte so eine Eingabe natürlich erlaubt sein.

Setzt man oben den Datentyp auf Decimal(18,14), dann crasht das.

Ergänzt man

CODE
Where A.AdressenId <> 155


dann funktioniert das. Es ist genau dieser Datensatz.


--------------------
Web-Anwendung 3.0: Ein Online-Kalender für Termine vieler Filialen.

server-daten - die Single-Data-Solution: Web-Datenbanken als Online - CRM - Lösung.
Ihre Geschäftsprozesse entscheiden, was Ihre Online-Datenbank macht. Sie konzentrieren sich auf Ihr Kerngeschäft - Ihre Datenbank funktioniert.
Top
PMEmail PosterUsers Website
Top
 
Maik
power-labels AG
#6 Geschrieben am: Di 29.07.2008, 18:41 (+01:02)
Report PostQuote Post

AyomRank 5
**********

Gruppe: Member (aktiv)
Beiträge: 485
Mitglied seit: 16.03.2006


Kenne das Problem zwar nicht (wegen MySQL smile.gif ) aber für eine unserer Umkreissuchen haben wir einen kleinen Kniff angewendet um die Sache zu Beschleunigen.

Und zwar, wenn du nicht gerade den ganzen Globus als Quelle hast, sondern nur zB.: DE,AT,CH dann kannst du eine Annäherung machen, denn in dieser Gegend sind die Abstände der Längenkreise fast konstant. Da reicht dann also alleine der Satz des Pythagoras.

Bei uns ergab das eine max. Abweichung von ~2% aber die Abfrage war insgesamt glaube 5 mal so schnell.


--------------------
Top
PMEmail PosterUsers WebsiteICQ
Top
 
jAuer
Jürgen Auer - freiberufl. Programmierer
#7 Geschrieben am: Di 29.07.2008, 19:53 (+01:12)
Report PostQuote Post

AyomRank 9
Group Icon

Gruppe: Experten Entwicklung
Beiträge: 2432
Mitglied seit: 4.02.2006


QUOTE (Maik @ Di 29.07.2008, 18:41)
Bei uns ergab das eine max. Abweichung von ~2% aber die Abfrage war insgesamt glaube 5 mal so schnell.

Die Performance ist nicht das Problem.

Die Kundendatenbanken enthalten bsp. Mitgliederdaten, das sind dann 500 oder 2000 Zeilen mit Namen, Adresse und Geodaten. Aber die Tabellen sind damit immer noch höchstens wenige MB groß. Da hat der DbServer die ganze Tabelle im Arbeitsspeicher.

Damit dauert die reine Abfrage für die Umkreissuche bsp. 0.05 Sekunden - das ist problemlos (läßt sich mit .NET-Trace gut herausfinden bzw. als Problem ausschließen). Ein extrem fragmentierter Index in einer der OpenGeoDb-Tabellen war jetzt (unter dem Gesichtspunkt der Performance) viel problematischer - da hat die Ermittlung der Geokoordinaten zu einer PLZ 'etwas arg lange' gedauert.

Da das Problem allerdings strukturell existiert und es bei 'präziseren Variablen' eher auftritt, könnte es auch bei einer mySql-Variante - allgemeiner: bei jedem Db-Backend - sichtbar werden. Das Problem trat ja in den anderen Kundendatenbanken und auch in dieser noch nie auf - es ist eine Kombination aus 'speziellen Werten in der Tabelle' plus hierzu passender Nutzereingabe.

Man benötigt allerdings eine Alarmierungsfunktion - sonst bemerkt man das ja gar nicht.


--------------------
Web-Anwendung 3.0: Ein Online-Kalender für Termine vieler Filialen.

server-daten - die Single-Data-Solution: Web-Datenbanken als Online - CRM - Lösung.
Ihre Geschäftsprozesse entscheiden, was Ihre Online-Datenbank macht. Sie konzentrieren sich auf Ihr Kerngeschäft - Ihre Datenbank funktioniert.
Top
PMEmail PosterUsers Website
Top
 

#8 Geschrieben am: Do 31.07.2008, 14:41 (+42:47)
Report PostQuote Post

AyomRank 1
**

Gruppe: Member (inaktiv)
Beiträge: 0
Mitglied seit: --


QUOTE
Nach dem Start dieses Threads (die Lösung weiß ich seit heute früh) fiel mir auf, daß die Variante (2) crasht, falls man den Datentyp von @i_latitude_r / @i_longitude_r von Decimal(18,8) auf Decimal(18,14) verbessert.

Ist dein Lösung nun auf decimal(18,14) zu verzichten?

Wenn der händische Aufruf und die automatisch generierte Tabelle nicht sind m.E. die Datentypen in der automatischen Prozedur verschieden von dem händischne Ablauf.

Ich hatte mal den Fall eines "float" der nicht funktioniert hat, weil das bsp. 1.3434e-12 in einer Funktion weder in einen absolute Zahlenwert zurückgerechnet wurde und auch nicht weiterverarbeitet werden konnte. Hab ich die Funktion weggelassen und direkt in den code geschrieben, ging's. Warum weiss ich bis heute nicht.

Jedenfalls denke ich, dass das Datenformat im automatischen Aufruf nicht verarbeitbar ist.
In der Ergebniszeile steht:
155 51.49027615464600 7.49839939608644 0.89867485165970 0.13087175809126 0
Bei decimal(18,14) könnte m.E. wegen eines Fliesskommafehlers ein anderer Wert herauskommen, der mit dem Datentypen der Ergebnisausgabe nicht kompatibel ist. Hast du mal versucht das Ergebnis in der Ausgabe auf 14 Stellen zu runden?

Gruss
Tümmel




Top
PMEmail Poster
Top
 
Maik
power-labels AG
#9 Geschrieben am: Do 31.07.2008, 15:31 (+00:50)
Report PostQuote Post

AyomRank 5
**********

Gruppe: Member (aktiv)
Beiträge: 485
Mitglied seit: 16.03.2006


Es können auch Rundungsfehler sein die beim Umrechnen (hin und zurück) des Fixed-Point Formats so dumm enden, das ACos mit Werten ausserhalb des Funktionsbereichs gefüttert wird... zB. >1 oder <-1... Ansonsten wüßte ich auch keinen Grund mehr...


--------------------
Top
PMEmail PosterUsers WebsiteICQ
Top
 
jAuer
Jürgen Auer - freiberufl. Programmierer
#10 Geschrieben am: Do 31.07.2008, 17:57 (+02:26)
Report PostQuote Post

AyomRank 9
Group Icon

Gruppe: Experten Entwicklung
Beiträge: 2432
Mitglied seit: 4.02.2006


QUOTE (Maik @ Do 31.07.2008, 15:31)
Es können auch Rundungsfehler sein die beim Umrechnen (hin und zurück) des Fixed-Point Formats so dumm enden, das ACos mit Werten ausserhalb des Funktionsbereichs gefüttert wird... zB. >1 oder <-1...

Genau dies ist das Problem gewesen.

Intern wird ja zunächst addiert:

CODE
(SIN(A.latitude_r) * SIN(@i_latitude_r)) +
  (COS(A.latitude_r) * COS(@i_latitude_r) * COS(@i_longitude_r - A.longitude_r)


Bei zwei sehr nahe beieinanderliegenden Werten geht die Differenz

QUOTE
@i_longitude_r - A.longitude_r


gegen 0, der Cosinus davon gegen 1. Wenn sich die Steigungen von Sin/Cos für Latitude/Longitude um diese beiden Punkte stark voneinander unterscheiden, dann reicht das offenbar, um zumindest einen internen Wert > 1 zu erzeugen.

Der Gesamtausdruck muß aber <= 1 bleiben, weil nur das der Definitionsbereich der ACos-Funktion ist. Der Witz war: Fügte man oben etwas wie + 0.00001 dazu, dann crashte das sofort interaktiv mit derselben Fehlermeldung. Rechnete man die Summe direkt aus, kam 1 raus. Gleichzeitig führte aber die Verzweigung

CODE
Case
When Round(Abs(A.latitude_r - @i_latitude_r) + Abs(A.longitude_r - @i_longitude_r), 8) = 0 Then
Cast(0.0 As Decimal(18,14))
Else (ACos((SIN(A.latitude_r) * SIN(@i_latitude_r))
   (COS(A.latitude_r) * COS(@i_latitude_r) * COS(@i_longitude_r - A.longitude_r))
) * 6378.137) End As Distance


dazu, daß das Problem verschwand: Liegt die Summe der absoluten Differenzen beider Werte, gerundet auf 8 Stellen, bei 0, dann nimm gleich 0 als Entfernung, ansonsten berechne.

Nimmt man übrigens Decimal(38,36) (also so ziemlich die maximale Genauigkeit), dann funktioniert das auch wieder.

Und das Böse daran ist, daß ein solches Problem fast nicht zu erahnen ist. Ein solcher Domain-Error (fehlerhafter Eingabebereich für eine Funktion) kann mathematisch eigentlich nicht auftreten - und tritt in ganz seltenen Fällen eben doch auf. Insofern eine echte Race Condition.


--------------------
Web-Anwendung 3.0: Ein Online-Kalender für Termine vieler Filialen.

server-daten - die Single-Data-Solution: Web-Datenbanken als Online - CRM - Lösung.
Ihre Geschäftsprozesse entscheiden, was Ihre Online-Datenbank macht. Sie konzentrieren sich auf Ihr Kerngeschäft - Ihre Datenbank funktioniert.
Top
PMEmail PosterUsers Website
Top
 
Maik
power-labels AG
#11 Geschrieben am: Do 31.07.2008, 18:26 (+00:28)
Report PostQuote Post

AyomRank 5
**********

Gruppe: Member (aktiv)
Beiträge: 485
Mitglied seit: 16.03.2006


probier einfach mal einen kleinen "Hack", vielleicht hilft's ja:

CODE

ACos(
 (  
   (SIN(A.latitude_r) * SIN(@i_latitude_r)) +
   (COS(A.latitude_r) * COS(@i_latitude_r) * COS(@i_longitude_r - A.longitude_r))
 ) * 0.1 * 10
)


Ein Versuch ist's wert, ob's funktioniert weiß nur der Programmierer von MSSQL smile.gif


--------------------
Top
PMEmail PosterUsers WebsiteICQ
Top
 
jAuer
Jürgen Auer - freiberufl. Programmierer
#12 Geschrieben am: Fr 1.08.2008, 06:59 (+12:33)
Report PostQuote Post

AyomRank 9
Group Icon

Gruppe: Experten Entwicklung
Beiträge: 2432
Mitglied seit: 4.02.2006


QUOTE (Maik @ Do 31.07.2008, 18:26)
CODE

ACos(
 (  
   (SIN(A.latitude_r) * SIN(@i_latitude_r)) +
   (COS(A.latitude_r) * COS(@i_latitude_r) * COS(@i_longitude_r - A.longitude_r))
 ) * 0.1 * 10
)


Ein Versuch ist's wert, ob's funktioniert weiß nur der Programmierer von MSSQL smile.gif

Nee, so etwas hilft nichts.

Wenn man sich den generierten Ausführungsplan ansieht, dann gehen 66 % auf den clustered Index Scan, 44 % auf die Sortierung nach der berechneten Spalte - und 0 % auf die Berechnung des Ausdrucks.

Ich vermute ohnehin, daß der Optimierer die Konstanten zusammenzieht.

Die obige Case - Verzweigung, die effektiv verhindert, daß der Ausdruck berechnet wird, löst das Problem vollständig.

PS:

QUOTE (Maik @ Fr 1.08.2008, 08:07)
Probier es aus bevor du urteilst... in anderen Programmiersprachen geht es schließlich auch...


Natürlich habe ich das ausprobiert.


--------------------
Web-Anwendung 3.0: Ein Online-Kalender für Termine vieler Filialen.

server-daten - die Single-Data-Solution: Web-Datenbanken als Online - CRM - Lösung.
Ihre Geschäftsprozesse entscheiden, was Ihre Online-Datenbank macht. Sie konzentrieren sich auf Ihr Kerngeschäft - Ihre Datenbank funktioniert.
Top
PMEmail PosterUsers Website
Top
 
Maik
power-labels AG
#13 Geschrieben am: Fr 1.08.2008, 08:07 (+01:07)
Report PostQuote Post

AyomRank 5
**********

Gruppe: Member (aktiv)
Beiträge: 485
Mitglied seit: 16.03.2006


Probier es aus bevor du urteilst... in anderen Programmiersprachen geht es schließlich auch...


--------------------
Top
PMEmail PosterUsers WebsiteICQ
Top
 
Thema wird von 0 Benutzer(n) gelesen (0 Gäste und 0 anonyme Benutzer)
0 Mitglieder:
Trackback-Url: http://www.ayom.com/track/t/25545

Topic Options Reply to this topicStart new topicStart Poll

 


> Ähnliche Themen
Umkreissuche & Entfernung Daniel Cieslar 439 6 Fr 2.05.2008, 11:50
Sql Hardcore: Union in Unterabfragen - sortiert jAuer 809 4 Mo 24.12.2007, 11:34




Anzeige - [Hier werben / Mediadaten]



Anzeigen


[Hier werben / Mediadaten]