Announcement

Collapse
No announcement yet.

Performance einer Query

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

  • Performance einer Query

    Hallo,

    ich habe zwei Tabellen, eine Teilnehmertabelle und eine Teilnahmentabelle.

    Der Einfachheit halber besteht im Folgenden die Teilnehmertabelle nur aus der id (primary key), die Teilnahmentabelle aus id, teilnehmer_id und veranstaltungs_id.

    Es gibt Teilnehmer, die bisher in der Teilnahmentabelle noch nicht vorhanden sind, z.B. weil die Veranstaltung noch nicht stattgefunden hat.

    Ich möchte nun eine performante Query erstellen, die mir die Teilnehmer ausgibt und dabei einen Flag, ob sie bereits in der Teilnahmentabelle vorhanden sind.

    Mein Ansatz
    PHP Code:
    SELECT 
        t
    .id
        
    1-(GROUP_CONCAT(p.id) <=> NULL) AS istEchterTeilnehmer 
    FROM teilnehmer t
    LEFT JOIN teilnahmen p ON p
    .teilenehmerid t.id
    GROUP BY t
    .id 
    funktioniert, ist aber sehr langsam. Für eine Performancemessung habe ich zunächst von einer Indizierung abgesehen.

    Welche besseren Alternativen existieren zu meinem Konstrukt?
    Ich möchte aus Wartbarkeitsgründen von Queries absehen, die UNION WHERE EXISTS/ NOT EXISTS beinhalten, weil die eigentliche Query sehr groß ist, und dann der SQL-Code prinzipiell doppelt vorhanden wäre.

    Danke,

    m(y/s)slqer

  • #2
    Originally posted by mssqler View Post
    Hallo,

    ich habe zwei Tabellen, eine Teilnehmertabelle und eine Teilnahmentabelle.

    Der Einfachheit halber besteht im Folgenden die Teilnehmertabelle nur aus der id (primary key), die Teilnahmentabelle aus id, teilnehmer_id und veranstaltungs_id.

    Es gibt Teilnehmer, die bisher in der Teilnahmentabelle noch nicht vorhanden sind, z.B. weil die Veranstaltung noch nicht stattgefunden hat.

    Ich möchte nun eine performante Query erstellen, die mir die Teilnehmer ausgibt und dabei einen Flag, ob sie bereits in der Teilnahmentabelle vorhanden sind.
    Code:
    test=*# select * from teilnehmer ;
     id | name
    ----+-------
      1 | Max
      2 | Peter
      3 | Hans
    (3 rows)
    
    Time: 0,152 ms
    test=*# select * from teilnahmen ;
      event  | teilnehmer
    ---------+------------
     event 1 |          2
     event 2 |          2
    (2 rows)
    
    Time: 0,166 ms
    test=*# select t.id, t.name, p.event, case when event is null then 'Anfänger' end from teilnehmer t left join teilnahmen p on t.id=p.teilnehmer;
     id | name  |  event  |   case
    ----+-------+---------+----------
      2 | Peter | event 1 |
      2 | Peter | event 2 |
      1 | Max   |         | Anfänger
      3 | Hans  |         | Anfänger
    (4 rows)

    funktioniert, ist aber sehr langsam.
    Explain wurde schon erfunden (bei MySQL zwar wenig hilfreich, aber nutze es.

    Für eine Performancemessung habe ich zunächst von einer Indizierung abgesehen.
    Für einen Sehtest habe ich mir die Augen verbunden.


    Andreas

    Comment


    • #3
      Erst einmal danke für die Antwort.

      Explain habe ich laufen lassen, ist nicht so aussagekräftig.
      Indizierung abzuschalten bringt immer etwas für qualitative Aussagen, manchmal mehr als explain.
      Von daher ist der Vergleich des Sehtests mit verbundenen Augen hier unangebracht, aber hat zu meiner Belustigung beigetragen.

      Trotzdem sehr nett, wie Du hier die Entwicklung der Query skizzierst.
      Ich entnehme Deiner Aussage die Ersetzung von GROUP_CONCAT durch CASE ... WHEN ... END.

      Originally posted by akretschmer View Post
      Code:
      test=*# select * from teilnehmer ;
       id | name
      ----+-------
        1 | Max
        2 | Peter
        3 | Hans
      (3 rows)
      
      Time: 0,152 ms
      test=*# select * from teilnahmen ;
        event  | teilnehmer
      ---------+------------
       event 1 |          2
       event 2 |          2
      (2 rows)
      
      Time: 0,166 ms
      test=*# select t.id, t.name, p.event, case when event is null then 'Anfänger' end from teilnehmer t left join teilnahmen p on t.id=p.teilnehmer;
       id | name  |  event  |   case
      ----+-------+---------+----------
        2 | Peter | event 1 |
        2 | Peter | event 2 |
        1 | Max   |         | Anfänger
        3 | Hans  |         | Anfänger
      (4 rows)


      Explain wurde schon erfunden (bei MySQL zwar wenig hilfreich, aber nutze es.



      Für einen Sehtest habe ich mir die Augen verbunden.


      Andreas
      Zuletzt editiert von mssqler; 19.02.2013, 11:23.

      Comment


      • #4
        Indizierung abzuschalten bringt immer etwas für qualitative Aussagen,
        Nein. Die einzige Aussage die du erhältst ist wie sich die Queries ohne Indizes verhalten sonst nix. Wenn du Queries ohne Indizes vergleichst hat das keinerlei Aussagekraft darüber wie sich die Queries relativ zueinander später mit Indizes verhalten werden. Indizes sind ja nicht einfach ein Faktor der nachher auf die Performance draufgerechnet wird. Also wenn du nicht gerade vorhast auf Indizes grundsätzlich zu verzichten ist deine Performancemessung in der Form sinnfrei.

        Comment


        • #5
          Originally posted by mssqler View Post
          Erst einmal danke für die Antwort.

          Explain habe ich laufen lassen, ist nicht so aussagekräftig.
          Indizierung abzuschalten bringt immer etwas für qualitative Aussagen, manchmal mehr als explain.
          Von daher ist der Vergleich des Sehtests mit verbundenen Augen hier unangebracht, aber hat zu meiner Belustigung beigetragen.

          Das das EXPLAIN von MySQL für die Tonne ist, ist mir bekannt. Nicht nur deswegen nutze ich auch kein MySQL.

          Das mit den Index abschalten und so von Dir ist aber falsch. Das merkst Du spätestens dann, wenn Du mal ein 'richtiges' Explain siehst, z.B. von PG, und verstehst, wie sich das zusammensetzt. Also all der ganze Dunstkreis Statistiken, Kostenmodell und so weiter.

          Wenn Dir das mit dem Sehtest nicht gefällt, dann mache einen Speedtest mit Deinem Auto. Baue aber vorher die Räder ab.


          Andreas

          Comment


          • #6
            Wieso zum Henker machts du in deiner Query ein group_concat?

            Sowas müsste doch auch reichen?
            Code:
            SELECT 
                t.id, 
                count(p.id) AS istEchterTeilnehmer 
            FROM teilnehmer t
            LEFT JOIN teilnahmen p ON p.teilenehmerid = t.id
            GROUP BY t.id
            Damit hättest du mal den langsam Vergleich auf Null eliminiert. Damit du wirklich ein Flag hast, müsstest du hier natürlich noch irgendwas im Stil von CASE WHEN count() > 0 then 1 else 0 end as ... drumrum bauen.
            LEFT (OUTER) Joins sind allerdings immer performancekiller - egal auf welcher Technologie die DB läuft. Als Lösungsansatz könntest du sonst versuchen das ganze in einen STRAIGHT JOIN umzubauen - wirkt unter mySQL manchmal wunder.

            Die Indexierung zu deaktivieren hilft höchstens dabei den Disk IO deines DB-Servers zu messen - aber keinesfalls die Query zu optimieren. Lieber ein vernünftiges Datenset generieren damit du auch gleich weisst ob das ganze in 2 Jahren auch noch funktioniert.

            Comment

            Working...
            X