Announcement

Collapse
No announcement yet.

Performanceproblem mit Umkreissuche

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Performanceproblem mit Umkreissuche

    Tach,

    ich habe eine Umkreissuche Programmiert mit Daten von obengeodb.

    Da ich wissen wollte wie sich meine Seite bei ein paar Datensätzen in der Db macht habe ich mir mal ein paar angelegt.

    Leider musste ich feststellen, das sehr schnell schluss ist.
    Ab 5000 Datensätzen wird es erheblich langsam und führt nicht nur selten zu einem Timeout,.

    Folgende Abfragen lasse ich auf die DB los.

    PHP Code:
    <?php
    //###########################################################
    // Einfache suche
    if ($_GET['action'] == 'search')
    {
        
    // Suche
        
    if (!isset($_GET['cat']))
        {
            
    $plz $_POST["plz"];
            
    $umkreis $_POST["umkreis"]; 
            
            
    $db = new db($schema);
            
    $laenge_breite mysql_query("SELECT laenge, breite FROM orte WHERE plz = $plz");
            
    $Laenge_breitearray mysql_fetch_array($laenge_breite);
            
    $_SESSION['plz'] = $plz;
            
    $_SESSION['umkreis'] = $umkreis;
        }
        else 
        {
            
    $plz $_SESSION["plz"];
            
    $umkreis $_SESSION["umkreis"]; 
            
            
    $db = new db($schema);
            
    $laenge_breite mysql_query("SELECT laenge, breite FROM orte WHERE plz = $plz");
            
    $Laenge_breitearray mysql_fetch_array($laenge_breite);
        }
        
        
    $laenge=$Laenge_breitearray[0] / 180 M_PI// Umrechnung von GRAD IN RAD
        
    $breite=$Laenge_breitearray[1] / 180 M_PI// Umrechnung von GRAD IN RAD
        
        //##################################################################
        // Blätterfunktion einrichten 
        
    $db = new db($schema);
        
    $pp = new LoadPP(); 
        
    $pp->params "page=search&action=search&"
        
    $pp->ppage 20;
        
    $count mysql_query("
        SELECT      
        e.event_id,    
        (6367.41*SQRT(2*(1-cos(RADIANS(breite))   
        *cos("
    .$breite.")*(sin(RADIANS(laenge))   
        *sin("
    .$laenge.")+cos(RADIANS(laenge))   
        *cos("
    .$laenge."))-sin(RADIANS(breite))   
        *sin("
    .$breite."))))    
        AS Distance    
        FROM    
        orte AS o   
        JOIN   
        event AS e   
        ON o.plz = e.plz    
        WHERE  
        e.gespert = 0  
        AND     
        6367.41*SQRT(2*(1-cos(RADIANS(breite))   
        *cos("
    .$breite.")   
        *(sin(RADIANS(laenge))   
        *sin("
    .$laenge.")+cos(RADIANS(laenge))   
        *cos("
    .$laenge."))-sin(RADIANS(breite))   
        *sin("
    .$breite."))) <= ".$umkreis."
        OR e.plz = '
    $plz'   
        ORDER BY Distance"
    );  
        
    $pp->NumRow mysql_num_rows($count); 
        
    $sites $pp->site_divide();
        
    //Blätterfunktion ende
        
        // Berechnen aller PLZ die in dem angegebenen Umkreis sind 
        
    $db = new db($schema);
        
    $events $db->getmatrix(
        SELECT    
        o.ort,   
        o.plz,  
        e.event_id,   
        e.kat_id,   
        e.titel,   
        e.fsa_datum,   
        e.location,  
        k.kategorie,  
        b.thumb,  
        (6367.41*SQRT(2*(1-cos(RADIANS(breite))   
        *cos("
    .$breite.")*(sin(RADIANS(laenge))   
        *sin("
    .$laenge.")+cos(RADIANS(laenge))   
        *cos("
    .$laenge."))-sin(RADIANS(breite))   
        *sin("
    .$breite."))))    
        AS Distance    
        FROM    
        orte AS o   
        JOIN   
        event AS e   
        ON o.plz = e.plz  
        JOIN  
        event_kat AS k  
        ON e.kat_id = k.kat_id  
        LEFT JOIN  
        bilder AS b  
        ON e.event_id = b.event_id OR b.event_id IS NULL  
        WHERE  
        e.gespert = 0  
        AND     
        6367.41*SQRT(2*(1-cos(RADIANS(breite))   
        *cos("
    .$breite.")   
        *(sin(RADIANS(laenge))   
        *sin("
    .$laenge.")+cos(RADIANS(laenge))   
        *cos("
    .$laenge."))-sin(RADIANS(breite))   
        *sin("
    .$breite."))) <= ".$umkreis."
        OR e.plz = '
    $plz'
        ORDER BY Distance DESC LIMIT 
    $start,".$pp->ppage."");

        
    // Ausgabe des ergebnisses
        
    require_once($tmppfad.'show_ergebniss.php');
        
        
    // Wenn kein ergebniss mach irgendwas
    }

    Die Rechnung ist sicherlich sehr Zeitraubend aber doch von nöten.

    Hat von euch jemand ein Tip wie ich das ganze schneller lösen könnte?

  • #2
    Tach auch,

    deine Berechnungen mit cos, sin, etc. sind sicherlich sehr unperformant und da sie auch in WHERE-Klauseln auftauchen kann MySQL hier auch keine Indizes verwenden.
    Ich würde folgendermasen vorgehen:

    1. Die notwendigen Berechnungen mit Datenbankfeldern (cos(RADIANS(breite), cos(RADIANS(laenge), etc.) würde ich beim INSERT einmal ausführen und die Ergebnisse in zusätzliche Datenbankfelder abspeichern.
    2. statische Berechnungen von Variablen würde ich einmal VOR der Abfrage ausführen und in separaten Variablen speichern, so daß sich die Rechenops im eigentlichen Statement auf +, - und * beschräncken.
    3. Evtl. läßt sich durch in 1.+2. beschriebene Redundanz ganz auch Rechenops im WHERE verzichten und damit die Felder vernünftig indizieren

    Gruß Falk
    Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

    Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

    Comment


    • #3
      Danke für deine Idee.

      Leider wüsste ich bei dieser rechnung nicht welche werte ich in der Tabelle Speichern könnte. Die Formel habe ich von opengeodb habe nur die Abfrage erweitert.

      Wenn ich alle joins mal wech nehmen und nur die Rechnung durchlaufen lassen auf alle 8180 PLZ habe ich ein Ergebniss in 0.4sek.

      Dann weiß ich welche PLZ in diesem angegebenen Umkreis ist.

      Kann ich nicht mit ein Subselect irgendwie vermeiden das er das er für jedes Event die 8180 PLZ durchrechnet?

      Weil das ja eigentlich auch das was dann richtig Zeit kostet.

      Leider habe ich bis noch nicht mit einem subselect gearbeitet.

      Comment


      • #4
        Ist auf der PLZ-Spalte jeweils ein Index?
        Gibt es eine Möglichkeit diesen Index als UNIQUE einzurichten?
        Haben die Tabellen Primärschlüssel und lassen sich diese in der Abfrage verwenden?

        Schau dir ggfs. mal mit EXPLAIN an, wo für deine Abfrage Indizierungsbedarf besteht.

        Gruß Falk
        Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

        Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

        Comment


        • #5
          Ist auf der PLZ-Spalte jeweils ein Index?
          ja auf PLZ ist jewals ein Index.

          Gibt es eine Möglichkeit diesen Index als UNIQUE einzurichten?
          Lokal auf meinem Rechner geht es auf jeden fall auf dem Webspace kann ich dir das grade nicht sagen. Werde aber noch diesen monat zugang zu meinem Root Server bekommen.

          Haben die Tabellen Primärschlüssel und lassen sich diese in der Abfrage verwenden?
          Es gibt Primärschlüssel glaube aber nicht das diese sich verwenden lassen.
          In der Tabell Event gibt es die event_id. Ich poste dir einfach mal das designe der tabelle.

          Die tabelle orte
          Code:
          CREATE TABLE `orte` (
            `ort_id` int(11) NOT NULL,
            `staat` varchar(2) character set utf8 NOT NULL,
            `bundesland` varchar(2) character set utf8 NOT NULL,
            `regierungsbezirk` varchar(50) character set utf8 NOT NULL,
            `landkreis` varchar(50) character set utf8 NOT NULL,
            `verwaltungszusammenschluss` varchar(100) character set utf8 NOT NULL,
            `ort` varchar(100) character set utf8 NOT NULL,
            `laenge` double NOT NULL,
            `breite` double NOT NULL,
            `plz` smallint(5) NOT NULL,
            KEY `ort_id` (`ort_id`),
            KEY `plz` (`plz`),
            KEY `breite` (`breite`),
            KEY `laenge` (`laenge`)
          ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
          und die Tabelle event
          Code:
          CREATE TABLE `event` (
            `event_id` int(11) NOT NULL auto_increment,
            `kat_id` int(11) NOT NULL,
            `user_id` int(11) NOT NULL,
            `erstellt` date NOT NULL,
            `titel` varchar(200) collate latin1_general_ci NOT NULL,
            `location` varchar(200) collate latin1_general_ci NOT NULL,
            `strasse` varchar(200) collate latin1_general_ci NOT NULL,
            `hausnummer` varchar(10) collate latin1_general_ci NOT NULL,
            `plz` varchar(5) collate latin1_general_ci NOT NULL,
            `ort` varchar(200) collate latin1_general_ci NOT NULL,
            `hotline` varchar(200) collate latin1_general_ci NOT NULL,
            `hotmail` varchar(250) collate latin1_general_ci NOT NULL,
            `thotline` varchar(200) collate latin1_general_ci NOT NULL,
            `thotmail` varchar(250) collate latin1_general_ci NOT NULL,
            `fsa_datum` date NOT NULL,
            `ugb_datum` date NOT NULL,
            `fsu_zeit` varchar(20) collate latin1_general_ci NOT NULL,
            `ugb_zeit` varchar(20) collate latin1_general_ci NOT NULL,
            `beschreibung` text collate latin1_general_ci NOT NULL,
            `freigabe` varchar(200) collate latin1_general_ci NOT NULL,
            `einlasskreterien` text collate latin1_general_ci NOT NULL,
            `abendkasse` varchar(100) collate latin1_general_ci NOT NULL,
            `ticketvorverkauf` varchar(100) collate latin1_general_ci NOT NULL,
            `gespert` int(1) NOT NULL,
            `spergrund` text collate latin1_general_ci NOT NULL,
            PRIMARY KEY  (`event_id`),
            KEY `kat_id` (`kat_id`)
          ) ENGINE=MyISAM  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=40901 ;
          Die Tabelle event wir noch umgestellt auf utf8

          Mit den Indexen habe ich des öfteren mal das eine oder andere ausprobiert.

          Was mit dem Unique ist, das müsstest du mir noch mal erklären.

          Comment


          • #6
            Hallo,

            du verwendest event.plz sowohl im Join als auch als Where-Bedingung. Dort würde ich auf alle Fälle noch einen Index anlegen.

            Warum Unique-Index: Auf einen Unique-Index kann u.U. sehr viel schneller zugegriffen werden, deshalb sollte man auf Daten die von den Bedingungen her Unique sind, auch einen solchen Index legen.

            Gruß Falk
            Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

            Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

            Comment

            Working...
            X