[SQL] Query optimalisatie probleem (group by)

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • vorlox
  • Registratie: Juni 2001
  • Laatst online: 02-02-2022

vorlox

I cna ytpe 300 wrods pre miute

Topicstarter
Beste,

Ik zit met een probleempje qua optimalisatie van een query.

Even korte uitleg
Ik heb de volgende tabellen
s_fil = bestanden
s_fil_rol_rd = bestand schrijf rollen
s_fol = map namen
s_prt_grp_rol = koppeltabel rollen naar groepen
s_prt_grp_prt = koppeltabel groepen naar gebruikers

Een gebruiker kan dus in 1 of meerdere groepen zitten en elke groep kan 1 of meerdere rollen hebben
Verder heeft een bestand ook 1 of meerdere rollen.

Nu wilde ik dus graag met 1 query alle bestanden waar een gebruiker schrijf rollen voor heeft (of waar geen rollen gedefineerd zijn) ophalen.

Uiteindelijk kwam ik uit bij de volgende query.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    SELECT 
       a.id,
           a.name,
       s_fol.name foldername
    FROM 
       s_fil a
       INNER JOIN s_fol ON a.s_fol_id = s_fol.id
       LEFT OUTER JOIN s_fil_rol_rd b ON a.id = b.s_fil_id
       LEFT OUTER JOIN s_prt_grp_rol d ON b.s_rol_id = d.s_rol_id
       LEFT OUTER JOIN s_prt_grp_prt e ON d.s_prt_grp_id = e.s_prt_grp_id
    WHERE 
      (e.s_prt_id = 3 OR e.s_prt_id IS NULL)
    GROUP BY
        a.id, a.name, s_fol.name
    ORDER BY NULL


Nu is echter de explain output alsvolgt.
Hij gebruikt een temp table
idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEs_folindexPRIMARY,ids_fol_name_idx76837Using index; Using temporary
1SIMPLEarefs_fil_s_fol_fks_fil_s_fol_fk8synone.s_fol.id5
1SIMPLEbrefPRIMARYPRIMARY8synone.a.id1Using index
1SIMPLEdrefs_prt_grp_rol_s_rol_fks_prt_grp_rol_s_rol_fk8synone.b.s_rol_id1Using index
1SIMPLEerefs_prt_grp_prt_s_prt_grp_fks_prt_grp_prt_s_prt_grp_fk8synone.d.s_prt_grp_id1Using where; Using index


Echter als ik hem zonder de join naar s_fol (mappen) doe dus zoeits als
code:
1
2
3
4
5
6
7
8
9
10
11
12
    SELECT 
       a.id,
           a.name
    FROM 
       s_fil a
       LEFT OUTER JOIN s_fil_rol_rd b ON a.id = b.s_fil_id
       LEFT OUTER JOIN s_prt_grp_rol d ON b.s_rol_id = d.s_rol_id
       LEFT OUTER JOIN s_prt_grp_prt e ON d.s_prt_grp_id = e.s_prt_grp_id
    WHERE 
      (e.s_prt_id = 3 OR e.s_prt_id IS NULL)
    GROUP BY
        a.id, a.name


Dan is de explain alsvolgt
idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1SIMPLEaindexdsad342775273Using index
1SIMPLEbrefPRIMARYPRIMARY8synone.a.id1Using index
1SIMPLEdrefs_prt_grp_rol_s_rol_fks_prt_grp_rol_s_rol_fk8synone.b.s_rol_id1Using index
1SIMPLEerefs_prt_grp_prt_s_prt_grp_fks_prt_grp_prt_s_prt_grp_fk8synone.d.s_prt_grp_id1Using where; Using index


Nu gebruikt hij geen temp table

Kan het komen doordat ik in de group by (groepeer op kolommen uit 2 tabellen dat mysql daar dus altijd een temp van moet maken)
of is er een andere manier om dit te voorkomen

Ik heb het net ook geprobeerd via een subquery....maar dit duurt meteen 1.4 sec in MySQL
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    SELECT
       a.id,
           a.name,
       s_fol.name foldername
    FROM 
       s_fil a
       INNER JOIN s_fol ON a.s_fol_id = s_fol.id
    WHERE a.id IN (
    
        SELECT 
           a.id
        FROM 
           s_fil a
           LEFT OUTER JOIN s_fil_rol_rd b ON a.id = b.s_fil_id
           LEFT OUTER JOIN s_prt_grp_rol d ON b.s_rol_id = d.s_rol_id
           LEFT OUTER JOIN s_prt_grp_prt e ON d.s_prt_grp_id = e.s_prt_grp_id
        WHERE 
          (e.s_prt_id = 3 OR e.s_prt_id IS NULL)
        GROUP BY
            a.id
    )

idselect_typetabletypepossible_keyskeykey_lenrefrowsExtra
1PRIMARYs_folindexPRIMARY,ids_fol_name_idx76837Using index
1PRIMARYarefs_fil_s_fol_fks_fil_s_fol_fk8synone.s_fol.id5Using where
2DEPENDENT SUBQUERYaindexPRIMARY8273Using index
2DEPENDENT SUBQUERYbrefPRIMARYPRIMARY8synone.a.id1Using index
2DEPENDENT SUBQUERYdrefs_prt_grp_rol_s_rol_fks_prt_grp_rol_s_rol_fk8synone.b.s_rol_id1Using index
2DEPENDENT SUBQUERYerefs_prt_grp_prt_s_prt_grp_fks_prt_grp_prt_s_prt_grp_fk8synone.d.s_prt_grp_id1Using where; Using index

[ Voor 22% gewijzigd door vorlox op 07-03-2009 14:53 ]


Acties:
  • 0 Henk 'm!

  • Miyamoto
  • Registratie: Februari 2009
  • Laatst online: 06:25
Geen antwoord op je vraag, maar ik dacht dat SQL een beschrijvende taal was, waarbij het dus niet uitmaakt hoe de query geformuleerd wordt?

Acties:
  • 0 Henk 'm!

  • vorlox
  • Registratie: Juni 2001
  • Laatst online: 02-02-2022

vorlox

I cna ytpe 300 wrods pre miute

Topicstarter
Als je een fatsoenlijke database hebt is dat misschien zo, maar ik draai MySQL ;)

Het gaat erom hoe je query uitgevoerd wordt door de database, de database maakt een soort plan van aanpak aan de hand van je query...en soms kun je dat een beetje beinvloeden door de query anders op te bouwen. Vandaar de explain syntax om dit te controleren

[ Voor 62% gewijzigd door vorlox op 07-03-2009 14:54 ]


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Miyamoto schreef op zaterdag 07 maart 2009 @ 14:24:
Geen antwoord op je vraag, maar ik dacht dat SQL een beschrijvende taal was, waarbij het dus niet uitmaakt hoe de query geformuleerd wordt?
Moet je eens met Oracle bezig gaan, daar moet je veelal met 'hits' aangeven dat 'ie eerst op basis van de keys een zo klein mogelijke set op bouwt, en pas daarna de rest van het werk doet. Begin nu ook te begrijpen waarom Oracle DBA's zoveel verdienen: het is kutwerk en je hebt ze echt nodig :)

https://niels.nu


Acties:
  • 0 Henk 'm!

  • winkbrace
  • Registratie: Augustus 2008
  • Laatst online: 24-08 15:17
Wat betreft je vraag:
Ik ben geen MySQL expert, maar je zou om je eigen vraag te beantwoorden eens kunnen proberen hoe je explain plan eruitziet zonder GROUP BY in je query. Verder ben ik wel benieuwd of het maken van een temp table de query trager maakt? Ik kan het wel begrijpen dat 'ie standaard een kleinere verzameling maakt door de inner join selectie eerst te doen en daar vervolgens dan de outer joins tegenaan te hangen over de index. Want wanneer je over de index gaat, moet je elk record er in opzoeken, dus zou het sneller kunnen zijn dat aantal eerst te reduceren.

Wat betreft de reacties:
@rooot: Het maakt alles uit hoe je je SQL statement schrijft!
Vergelijk deze twee queries maar even. Ze geven exact hetzelfde resultaat, maar de doorlooptijd zal aanzienlijk verschillen
SQL:
1
2
3
4
5
6
7
8
9
10
select id
,      (select datum
        from   big_table t2
        where  t.id = t2.id
       ) datum
from   big_table t

select id
,      datum
from   big_table t


Verder begrijp ik de sneer van Hydra naar Oracle niet. Oracle is juist behoorlijk intelligent in het zo efficiënt mogelijk uitvoeren van de query's. Gelukkig hebben ze je wel de mogelijkheid gegeven om door middel van 'hints' het explain plan bij te sturen mocht dat nodig zijn. In 90% van de gevallen echter is de query gewoon slechts geschreven (of soms is de database verkeerd ingericht)

Acties:
  • 0 Henk 'm!

Verwijderd

Ik zou sowieso geen joins gebruiken als ik jou was, dat neemt veel meer tijd in beslag.

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Verwijderd schreef op maandag 09 maart 2009 @ 15:24:
Ik zou sowieso geen joins gebruiken als ik jou was, dat neemt veel meer tijd in beslag.
Want? :X Heb je daar bronnen voor :?
Klinkklare onzin. Joins zijn er niet voor niets in een RDBMS.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
En in de context van mysql is een join juist meestal de snellere optie tov. IN() en subqueries. :P

{signature}


Acties:
  • 0 Henk 'm!

  • _js_
  • Registratie: Oktober 2002
  • Laatst online: 18-08 21:31
MySQL kan maar 1 index per tabel gebruiken in een query.
Om de s_fol tabel te joinen met a moet er naar het juiste id gezocht worden, hier zou een index op id dus kunnen helpen. Voor de group by op name is weer een index op name nodig. Als je zonder tijdelijke tabel wilt werken zou je een index over de beide kolommen name en id kunnen maken..
Pagina: 1