Toon posts:

[MySQL] Crash bij uitgebreide query*

Pagina: 1
Acties:

Verwijderd

Topicstarter
Het volgende probleem doet zich voor. Ik heb een database draaien met een aantal tabellen waaronder een postcode tabel met daarin foreign keys naar de tabellen plaats, gemeente, regio etc.

Nu doe ik de volgende query:

select postcode.postcode_id from postcode inner join plaats on postcode.plaats_id = plaats.plaats_id inner join gemeente on postcode.gemeente_id = gemeente.gemeente_id inner join regio on postcode.regio_id = regio.regio_id

Mijn hele computer freezed als ik deze query uitvoert in MYSQL. Enige optie is 2 sec de powerknop ingedrukt houden. 8)7

Deze query draait prima onder dezelfde database die op Ms SQL Server draait.. Dus het heeft iets met MySQL te maken..

Alle tabellen zijn geindexeerd. Het probleem ligt hem waarschijnlijk in het feit dat hij duizenden records terug krijgt, maar je zou toch denken dat mYSQL dat gewoon aankan.

  • Cyphax
  • Registratie: November 2000
  • Laatst online: 10:20

Cyphax

Moderator LNX
Welk OS? Moet niet zo heel veel uitmaken want dit moet inderdaad niet je PC crashen. Hoge load is 1 ding maar dit klopt inderdaad niet.
't is ook maar een simpele query verder. Hier is zonder meer info niet zoveel van te zeggen gok ik zo. Kijk even in de logs van je systeem..

Saved by the buoyancy of citrus


Verwijderd

Verwijderd schreef op maandag 02 mei 2005 @ 11:49:
Alle tabellen zijn geindexeerd. Het probleem ligt hem waarschijnlijk in het feit dat hij duizenden records terug krijgt, maar je zou toch denken dat mYSQL dat gewoon aankan.
Heb je al getest met een LIMIT erachter? Dan weet je iig of het hier aan ligt.

  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 12:02
Je zou met een EXPLAIN even kunnen kijken of er daadwerkelijk indexen worden gebruikt. Daarnaast kun je door gewoon even te testen met een LIMIT van pak 'm beet 1000 records kijken of het in de query zit of in het aantal records.

Bij grote hoeveelheden records kan een unbuffered query ook helpen. Dat scheelt dan nogal in de hoeveelheid benodigd geheugen.

Regeren is vooruitschuiven


  • Mir
  • Registratie: Maart 2001
  • Niet online

Mir

Is dit niet mooier om te doen?

(en kan wellicht het crashen tegengaan?)

code:
1
2
3
4
5
6
7
8
9
10
11
12
select
    pc.postcode_id
from
    postcode pc
inner join
    plaats pl,
    gemeente g,
    regio r
on
    pc.plaats_id = pl.plaats_id
AND pc.gemeente_id = g.gemeente_id
AND pc.regio_id = r.regio_id

Verwijderd

Topicstarter
Ik draai zelf XP, maar hij geeft dezelfde fout bij m'n provider (linux servers) (daar hangen overigens de servers niet maar krijg ik een dikke timout).. Ik zal het eens proberen met een limit..

Het p.regio_id = r.regio_id etc heb ik al geprobeerd met hetzelfde resultaaat.

[ Voor 5% gewijzigd door Verwijderd op 02-05-2005 12:07 ]


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 06-05 18:51

Creepy

Tactical Espionage Splatterer

En je indexen zijn wel zo gelegd dat je queries er gebruik van kunnen maken? ;) (lees: op de velden van je where). Je kan checken met de EXPLAIN functie of dat zo is.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • djluc
  • Registratie: Oktober 2002
  • Laatst online: 07-05 19:46
Hoe groot zijn de tabellen? En gebruik je ook de juiste data-typen in je database?

Verwijderd

Topicstarter
Dit is de query die ik nu uitvoer:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
EXPLAIN
SELECT garage.garage_id
FROM garage_dienst
INNER JOIN dienst
  ON garage_dienst.dienst_id = dienst.dienst_id
RIGHT OUTER JOIN gemeente
  INNER JOIN postcode
    INNER JOIN plaats
      ON postcode.plaats_id = plaats.plaats_id
    INNER JOIN provincie
      ON postcode.provincie_id = provincie.provincie_id
    INNER JOIN regio
      ON postcode.regio_id = regio.regio_id
    ON gemeente.gemeente_id = postcode.gemeente_id
  RIGHT OUTER JOIN garage_auto
    INNER JOIN auto
      ON garage_auto.auto_id = auto.auto_id
    RIGHT OUTER JOIN garage
      ON garage_auto.garage_id = garage.garage_id
    ON plaats.plaats_id = garage.plaats_id
  ON garage_dienst.garage_id = garage.garage_id
WHERE auto.auto_id = 5
GROUP BY garage.garage_id


Daaruit komt de volgende tabel:

tabletypepossible_keyskeykey_lenrefrowsExtra
autoconstPRIMARYPRIMARY4const1Usingindex;Usingtemporary;Usingfilesort
gemeenteindexNULLPRIMARY4NULL468Usingindex
postcodeindexINDEXINDEX20NULL4770Usingindex
provincieeq_refPRIMARYPRIMARY4postcode.provincie_id1Usingindex
garage_autoindexINDEXINDEX10NULL2403Usingwhere;Usingindex
garage_dienstindexNULLINDEX10NULL16021Usingindex
plaatseq_refPRIMARYPRIMARY4postcode.plaats_id1Usingindex
garageeq_refPRIMARYPRIMARY4garage_auto.garage_id1
diensteq_refPRIMARYPRIMARY4garage_dienst.dienst_id1Usingindex
regioeq_refPRIMARYPRIMARY4postcode.regio_id1Usingindex


Mijn excuses voor het even niet netjes in een tabel zetten.

[ Voor 141% gewijzigd door NMe op 02-05-2005 13:41 . Reden: Je had in plaats van excuses maken ook gewoon netjes je post kunnen opmaken. ;) ]


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 12:02
Verwijderd schreef op maandag 02 mei 2005 @ 12:50:
de postcode tabel is 12 velden lang waarvan 5 foreign keys op datatype int(11)..
er zitten 4800 records in..
Een int(11) is natuurlijk wáy overkill voor postcodes. In Nederland zijn er maximaal 10.000*262 postcodes mogelijk (int(7) voldoet qua PC-id). Er zijn iets minder dan 500 gemeenten (smallint(3) voor gemeente-id)) en dus nog minder regio's (tinyint(3) allicht voldoende). Qua plaatsen weet ik niet exact hoeveel, maar met 10.000 (smallint(4)) zit je redelijk safe lijkt me zo.

Als je met 4800 records al een time-out krijgt zit er trouwens iets gruwelijk mis in je database. Of je hebt héél weinig geheugen. Ter illustratie: mijn K6-III met 228Mb ram crasht pas als je 400.000+ records met 300kolommen probeert op te halen.

Heb je al geprobeerd om een EXPLAIN query te doen, welke indexen gebruikt MySQL wanneer je de query runt?

Regeren is vooruitschuiven


Verwijderd

Topicstarter
ik heb het hiervoor met gewoon INT(4) geprobeerd, maar aan hardware tekortkomingen ligt het niet.. Bij mijn provider (servers met 4GB geheugen) krijg ik hetzelfde probleem. Ik heb EXPLAIN gedaan en dat resulteerde in bovengenoemde tabel.

Maar begrijp ik het goed dat hij uit bovenstaande kolom een resultaat aan rows van het produkt van alle rows wil ophalen? Dat zouden er inderdaad veels te veel zijn. Maar wat vreemd dat MS SQL Server wel gewoon op deze query een prima resultaat geeft in <1sec.

[ Voor 36% gewijzigd door Verwijderd op 02-05-2005 13:43 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 07-05 22:49

curry684

left part of the evil twins

Je mist een index op garage, en probeer zeker in MySQL zoveel mogelijk LEFT joins ipv RIGHT joins te gebruiken (right joins correct optimaliseren is niet MySQL's sterkste kant en zou een verklaring kunnen zijn voor het probleem).
Verwijderd schreef op maandag 02 mei 2005 @ 13:38:
Maar begrijp ik het goed dat hij uit bovenstaande kolom een resultaat aan rows van het produkt van alle rows wil ophalen? Dat zouden er inderdaad veels te veel zijn.
Vooral 'using filesort' en 'using temporary' zijn erg pijnlijk in je EXPLAIN, en kunnen in de query die je geeft best wel eens betekenen dat er gigabytes aan data op disk wordt geschreven alvorens deze zo traag mogelijk te sorteren. In de MySQL manual staan goede voorstellen over hoe je filesort en temporary kunt elimineren.
Maar wat vreemd dat MS SQL Server wel gewoon op deze query een prima resultaat geeft in <1sec.
Je moet een stuk speelgoed ook niet met een professioneel DBMS vergelijken ;)

[ Voor 64% gewijzigd door curry684 op 02-05-2005 13:48 ]

Professionele website nodig?


Verwijderd

Topicstarter
Bedankt.. ik zal de opties filesort even bekijken..

De reden dat er op garage geen INDEX zit is omdat deze garage_id in geen enkele andere gebruikte tabel uit de query staat. En in garage is hij al PK

[ Voor 7% gewijzigd door Verwijderd op 02-05-2005 14:05 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 07-05 22:49

curry684

left part of the evil twins

Algemene stelregel voor 99% van de simpele databases: beter teveel indexen dan te weinig :) Zeker op alle frequent uitgevoerde SELECTs moet gewoon iedere join een index gebruiken (table scans doen pijnnnnn).

Professionele website nodig?


Verwijderd

Topicstarter
phpMyAdmin zegt dat je niet op een kolom zowel een PK als een INDEX mag gebruiken..

Overigens.. net even geprobeerd alle inner joins te vervangen voor a.key = b.key en de right joins vervangen voor left join... ziet er al een stuk beter uit!!! hij crasht in ieder geval niet meer..

Algemene stelregel: queries generereerd door MS SQL zomaar posten in MySQL werkt niet altijd :-)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 07-05 22:49

curry684

left part of the evil twins

Verwijderd schreef op maandag 02 mei 2005 @ 14:22:
phpMyAdmin zegt dat je niet op een kolom zowel een PK als een INDEX mag gebruiken..
Nogal wiedes, een PK is per definitie een index in MySQL :) Daarom moet je ook met multi-column indexes werken als je binnen MySQL's limitaties wil blijven. Het feit dat MySQL per gejoinde tabel maximaal 1 index kan toepassen gaat je heel snel op de zenuwen zitten ;)
Overigens.. net even geprobeerd alle inner joins te vervangen voor a.key = b.key
Da's equivalent?
en de right joins vervangen voor left join...
Je hebt hopelijk de hele query structureel herschreven daarvoor en niet simpel find/replace gedaan? :P
Algemene stelregel: queries generereerd door MS SQL zomaar posten in MySQL werkt niet altijd :-)
Nog een paar stelregels:
• Right join in MySQL is ruk.
• Indexes in MySQL zijn ruk.
• Rag er altijd een explain doorheen, en zorg voor combined indexes om filesorts en temporaries te elimineren :)

Stel dat je moet joinen op een tabel waar je vervolgens ook op moet filteren. Dan moet je dus een index leggen op (key, sortfield) zodat ie eerst kan joinen op het eerste deel van de index, en daarna op de subindex de resultaten kan filteren voordat ze in de resultset komen (en er dus een filesort nodig is). 2 afzonderlijke indexen voor die 2 operaties gebruiken kan ie tenslotte niet :)

Professionele website nodig?


Verwijderd

Topicstarter
Overigens.. net even geprobeerd alle inner joins te vervangen voor a.key = b.key
Da's equivalent?


Ja. (toch?).. nouja.. het gaat iets verder dan a=b...

garage.plaats_id = plaats.plaats_id zou hetzeflde moeten zijn als inner join plaats on garage.plaats_id = plaats.plaats_id

[ Voor 43% gewijzigd door Verwijderd op 02-05-2005 14:53 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 07-05 22:49

curry684

left part of the evil twins

Verwijderd schreef op maandag 02 mei 2005 @ 14:48:
Overigens.. net even geprobeerd alle inner joins te vervangen voor a.key = b.key
Da's equivalent?


Ja. (toch?).. nouja.. het gaat iets verder dan a=b...

garage.plaats_id = plaats.plaats_id zou hetzeflde moeten zijn als inner join plaats on garage.plaats_id = plaats.plaats_id
Er zijn 2 (volstrekst equivalente) manieren om een inner join te gebruiken:
SQL:
1
2
select * from tabelA, tabelB
where tabelA.foreign = tabelB.primary

En de ANSI-manier:
SQL:
1
2
select * from tabelA
inner join tabelB on tabelA.foreign = tabelB.primary

Needless to say dien je zoveel mogelijk de ANSI-manier te gebruiken, al is het maar omdat je de deprecated eerste syntax niet kunt combineren met outer joins en deze veel minder overzichtelijk is doordat je de te joinen tabel fysiek scheidt van de joinende conditie. Tis verder gewoon identiek en zal hetzelfde uitgevoerd worden tho.

Professionele website nodig?


Verwijderd

Topicstarter
mijn voorkeur gaat eigenlijk ook uit naar de INNER JOIN manier... mijn meester op school vond dat ook. }:O }:O
Pagina: 1