Suche optimale Indizierung

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Suche optimale Indizierung

    hallo,
    zunächst ein gruss an alle - dies ist mein erstes posting hier... ;-)

    so, jetzt aber zu meinem problem. sorry, wenn ich das problem ausführlich beschreibe - aber dann wisst ihr halt gleich, worums geht...

    ich hab eine mysql5-datenbank mit ca. 40 tabellen, von denen viele immer wieder über fremdschlüssel verknüpft werden müssen. um jetzt in der php-anwendung (CMS und frontend einer mit 6mio aufrufen frequentierten page) zentrale funktionen für anlegen und auslesen der foreign keys schreiben zu können, hab ich eine zentrale 'relations'-tabelle gemacht, die immer dann zwischen zwei tabellen sitzt, wenn diese per n:m-verbindung kombiniert werden müssen.
    um die u.u. gleichen kombinationen von zwei tabellen in der relationen-tabelle unterscheiden zu können, hab ich eine alias-spalte erzeugt, die die art der verbindung beschreiben soll und an die abfragende methode übergeben wird.

    die tabellenstruktur der tabelle sieht wie folgt aus:
    id - bigint(20)
    alias - varchar(30)
    master_group_id - varchar(30)
    master_content_id - int(11)
    foreign_group_id - varchar(30)
    foreign_content_id - int(11)
    reverse - tinyint

    wenn ich also jetzt für einen übergebenen datensatz die zugeordneten datensätze der anderen tabelle brauche, wird also der name der tabelle (group_id) und die id des ersten ('master')-datensatzes und der name der tabelle, mit den verknüpften datensätzen übergeben.
    da ich aber nicht festlegen wollte, dass man nur in eine richtung suchen kann (ich will ja die verknüpften datensätze von beiden richtungen finden können), können also master-tabelle und master-id in der relationen-tabelle auch als foreign-datensatz gespeichert sein - ich muss also beide varianten abfragen.

    da diese tabelle ständig abgefragt wird und die tabellen alle kreuz und quer verküpft sind, enhält diese auch sehr viele datensätze - derzeit etwa eine halbe mio.
    mir ist klar, dass zur optimierung der performance die text-spalten in numerische typen geändert werden müssen. ist klar, wird auch passieren. das ändert aber nix daran, dass ich für diese tabelle eine optimale indizierung brauche.

    hier noch kurz der query, wie er derzeit beim suchen der fremdschlüsselverknüpfungen aussieht:

    PHP-Code:
        public function get_fk_id_array($master_group_id$master_content_id$foreign_group_id$alias$reverse) {
            global 
    $modulogConf;
            if(
    $master_group_id != '' && $master_content_id != '' && $foreign_group_id != '' && $alias != '') {

                
    $sql "SELECT id, master_group_id, master_content_id, foreign_group_id, foreign_content_id 
    FROM modulogdb_relations WHERE reverse = '
    $reverse' AND alias = '$alias' AND ((master_group_id = '$master_group_id
    AND master_content_id = '
    $master_content_id' AND foreign_group_id = '$foreign_group_id
    AND foreign_content_id > 0) OR (master_group_id = '
    $foreign_group_id' AND foreign_group_id = '$master_group_id
    AND foreign_content_id = '
    $master_content_id' AND master_content_id > 0)) ORDER BY id";
                
    $recordset $this->conn->Execute($sql) or fehler($this->conn->ErrorMsg()."..."."(sql = $sql)"debug_backtrace());
    ... 
    ihr seht, dass die abfrage recht komplex ist. ich vermute auch, dass es an der indizierung liegt, dass mir der server gelegentlich bei einem seitenaufruf mit 99,9% cpu-last in die knie geht.

    gesucht wird halt immer nach genau zwei kombinationen:
    entweder
    master_group_id, master_content_id, foreign_group_id, alias, reverse
    oder
    foreign_group_id, foreign_content_id, master_group_id, alias, reverse

    das studium des mysql-handbuchs zu dem thema ist sehr, sehr umfrangreich und IMHO nicht immer leicht zu verstehen. vielleicht hat da jemand von euch mehr erfahrung, was die indizierung über mehrere spalten angeht, so wie es hier ja wohl der fall sein müsste.

    vielleicht ist ja auch der query schon 'suboptimal' - und es hat jemand ne idee, wie man das besser machen könnte... *hoff*

    ps: wenn ich die beiden zuletzt genannten spalten-kominationen als indizes anlege, mosert phpmyadmin, weil alias nicht in mehreren indizes vorkommen darf. also: ich komm grad nicht wirklich weiter...

    vielen dank im voraus

    gruss
    hans
    Zuletzt geändert von rockie667; 20.01.2007, 08:20.
    Je mehr Käse, desto mehr Löcher.
    Je mehr Löcher, desto weniger Käse.
    Ergo: Je mehr Käse, desto weniger Käse...

  • #2
    Ich rekapituliere: Du hast 40 Tabellen, mit Femdschlüsselbeziehungen untereinander.
    Um n:m-Relationen abbilden zu können, braucht man eine "Vermittlertabelle". Du hast aber nicht für jede Relation eine solche, sondern nur eine einzige.

    Das kann ja nicht gut gehen! Es drängeln sich alle Queries, die eine n:m-Relation abfragen auf dieser Tabelle. Bei schreibenden Queries wird das Locking zum Eiertanz.
    Gleichzeitig ist die Tabelle sicher sehr groß. Wenns nicht grad ne Heap-Tabelle ist oder komplett in den RAM passt, wird viel Zeit für Paging und Verdrängung verbraten.

    Warum machst du es nicht wie üblich mit einer Relationstabelle pro Relation? Damit verteilen sich alle Queries auf alle Tabellen und jede für sich so klein, dass die Indizes leicht zu pflegen sind.

    btw: http://dev.mysql.com/EXPLAIN

    Kommentar


    • #3
      okay, hab ich kapiert... werd ich mittelfristig auch umstellen...

      leider muss ich aber ne halbwegs kurzfristige lösung finden, mit der ich mir helfen kann, bis ich die tabellenstruktur bzw. den quellcode entsprechend geändert hab.

      würde nur gerne wissen, wie du in diesem fall die indizes setzen wüdest...

      dankeschön nochmal
      hans
      Je mehr Käse, desto mehr Löcher.
      Je mehr Löcher, desto weniger Käse.
      Ergo: Je mehr Käse, desto weniger Käse...

      Kommentar


      • #4
        Die Spalte ID ist vermutlich ein PK. Aber die ganze Spalte ist überflüssig. Entweder löschen oder zumindest keinerlei Key drauf setzen. Nimm also den PK mal weg und dann schau mit EXPLAIN, welche Keys ratsam wären - das hängt schließlich von deinen Queries ab, da kann man keine generelle Empfehlung geben.

        Aber eines kann ich mit Sicherheit sagen: Alle Spalten die *_id heißen sowie reverse und alias sollten offensichtlich numerischen Typs sein! Das würde schon mal einiges an Performance bringen.

        Allerdings erfordert es Änderungen am Code und wenn das momentan nicht möglich ist, dann leg einfach noch ein paar Riegel RAM nach, optimiere die MySQL-Konfiguration oder zieh notfalls mit der DB auf eine Maschine mit richtig Dampf.

        Kommentar


        • #5
          dank dir schon mal - den ram werd ich gleich mal von zwei auf vier gigabyte erhöhen. alle spalten auf int-typ umstellen wird im quellcode etwas aufwändiger werden. hab leider nicht viel zeit, um eine schnelle lösung hinzukriegen... wenn ich keine andere lösung finde, muss es ja irgendwie gehen...

          aber mal eine ganz dumme frage. gibts nicht evtl. ne möglichkeit, alle anfragen an die tabelle zunächst mysql-intern auf andere tabellen umzuileiten? so dass ich evtl. abhängig vom alias (ich hab bislang 13 aliase) die anfrage an eine andere tabelle schicken kann? würde dann also die tabelle in 13 einzelteile zerlegen... ich hab noch nie in mysql programmiert, deshalb kenne ich da nicht die möglichkeiten, um evtl. das problem darüber zu lösen. das wäre die lösung all meiner probleme...

          ich hoffe, du weisst in etwa, was ich meine. anfrage kommt an die tabelle, und dann ist in der db ein weiterleitungsmechanismus hinterlegt, der in abhängigkeit vom alias-feld die anfrage woanders hin schickt. mag sich jetzt für dich vielleicht naiv anhören, aber ich denke, mysql bietet bestimmt unendlich viele möglichkeiten, von denen ich noch keinen blassen schimmer hab...

          gruss
          hans
          Je mehr Käse, desto mehr Löcher.
          Je mehr Löcher, desto weniger Käse.
          Ergo: Je mehr Käse, desto weniger Käse...

          Kommentar


          • #6
            Ne, sowas wie mod_rewrite für MySQL gibts imho nicht.

            Kommentar


            • #7
              würdest du eine möglichkeit darin sehen, in ADOdb einzugreifen und daselbst etwa in der methode Execute den übergebenen sql-string abzufragen und ggf zu manipulieren?

              also etwa so, dass, falls der string die tabelle relations enthält, abhängig vom alias der tabellenname verändert wird? dass also, falls das feld alias etwa den wert 'personendaten' hat, nicht die tabelle relations sondern die tabelle relations_personendaten abgefragt wird.

              dann wäre zunächst eine brauchbare lösung gefunden, da ich dann die grosse relationentabelle in 13 kleinere tabellen splitten könnte. in obiger abfrage könnte man auch die strings durch die entsprechenden int-werte ersetzen - wäre also eine zentrale position, an der man diese entscheidende anpassung projektweit vornehmen könnte, ohne den sonstigen quellcode mühsam und zweitraubend anpassen zu müssen...

              bitte: mir ist klar, dass es natürlich äusserst heikel ist, im ADOdb-quellcode rumzufummeln. aber da würde ich nun mal grad ne gute (vermutlich die einzige) möglichkeit sehen, um das problem zu lösen.
              Zuletzt geändert von rockie667; 21.01.2007, 11:48.
              Je mehr Käse, desto mehr Löcher.
              Je mehr Löcher, desto weniger Käse.
              Ergo: Je mehr Käse, desto weniger Käse...

              Kommentar


              • #8
                Klar ist das eine Möglichkeit, aber zuerst sollte sicher sein, dass wirklich nur dieses Projekt die ADODB-Schnittstelle verwendet.

                Dann würde ich eine Zeit lang alle Queries loggen, die durch ADODB gehen. Das kannst du dir natürlich sparen, wenn du schon genau weißt, was du wie umzuschreiben hast und dass du dabei nicht übers Ziel hinaus schießt.

                Kommentar

                Lädt...
                X