[MySQL] hoe kan ik deze zoekactie het best aanpakken?

Pagina: 1
Acties:

  • SvMp
  • Registratie: September 2000
  • Niet online
Ik heb de volgende tabel:
code:
1
2
3
4
5
CREATE TABLE lokaties (
ID                 INTEGER UNSIGNED   NOT NULL   AUTO_INCREMENT,
naam               VARCHAR(40)        NOT NULL,
ligt_in            INTEGER UNSIGNED   NOT NULL,
soort              INTEGER UNSIGNED   NOT NULL,


ID en naam spreken voor zich.
ligt_in is een foreigh key naar dezelfde tabel, dus wijst naar een andere lokatie.

Soort is het soort lokatie.
Mogelijkheden zijn als volgt: provincie, gemeentelijke, plaats, wijk, buurt, straat.

Die ligt_in wordt gebruikt om aan te wijzen in welk 'grotere' gebied een bepaalde lokatie ligt. Zo ligt de "Kalverstraat" in de wijk/stadsdeel "Binnenstad", dat ligt in plaats "Amsterdam", provincie "Noord Holland". De ligt_in van Noord Holland is 0, wat betekent dat het in Nederland ligt dus niks groters dat in de tabel te vinden is. Zo worden lokaties geordend.

Die lokatie-tabel wordt gebruikt door een tabel nieuwsberichten. Elk nieuwsbericht speelt zich op bepaalde lokaties af. Dit kan provinciaal zijn, maar ook gericht op 1 bepaalde straat.

Stel nieuws heeft betrekking op de Kalverstraat. Dan is de lokatie Kalverstraat verbonden met het nieuwsbericht. Het nieuwsbericht speelt zich ook af in Noord Holland, daar ligt de Kalverstraat immers, maar dat staat niet opgeslagen in het nieuwsbericht. Evenmin dat in dit voorbeeld Amsterdam is gekoppeld aan het nieuwsbericht. Dat blijkt namelijk wel uit de ketting lokaties, redundantie. In de nieuwstabel staat alleen de kleinste relevante lokatie.

En nu het probleem: Ik wil MySQL (en PHP) laten zoeken naar nieuws-items in een bepaalde lokatie. Stel ik ga zoeken naar nieuws in Amsterdam, dan wordt een nieuwsbericht dat is gelinkt aan Kalverstraat niet direct gevonden. Het zoek-machanisme moet alle onderliggende lokaties van Amsterdam nagaan om tot een volledig resultaat te komen. Dat dient recursief te gebeuren, immers elk stadsdeel heeft weer buurten en buurten hebben straten en op al die lokaties kunnen nieuwsberichten van toepassing zijn. Dat levert een enorme berg queries op.

Natuurlijk kan ik met PHP eerst een array maken met ID's van lokaties die relevant zijn, en daarna met PHP een lijst met alle nieuwsberichten doorlopen, maar dat vreet geheugen en CPU-kracht.

Kan dit niet simpeler?

Is er niet een leuke MySQL query te bedenken waar die recursie al in zit?

Ik heb zelf het volgende bedacht:
Uit de waarde van ID moet al een hierarchische ordening blijken.
Er zijn 12 provincies, maximaal 100 gemeenten, per gemeente maximaal 100 plaatsen, maximaal 50 wijken, maximaal 50 buurten, maximaal 500 straten per buurt.

ID van een wijk is bijvoorbeeld ID[provincie]*(100+100+50+50+500) + ID[gemeente]*(100+50+50+500) + ID[plaats]*(50+50+500) + ID[wijk]*(50+500)

Door het ID van een bepaalde lokatie van de betreffende grotere lokaties af te laten hangen, krijg je bij elkaar horende lokaties bij elkaar, en hoef je alleen maar in je whereis-clause een ID-bereik aan te geven in je query.

Ik vind het echter geen schoonheidsprijs waard (bezwaar bijv.: systeem moet op de kop als er ineens gemeenten met 101 plaatsen ontstaan), dus betere oplossingen welkom.

[ Voor 10% gewijzigd door SvMp op 29-11-2004 01:26 ]


  • T-MOB
  • Registratie: Maart 2001
  • Laatst online: 23:51
Wat je wil kan volgens mij niet in een query (iig in mysql). Tenzij je je datamodel zo omgooid dat je een tabel Provincies, een tabel Gemeenten (volgens mij zijn er daar trouwens een krappe 500 van), een tabel Wijken, een tabel Buurten en een tabel Straten maakt. Aangezien deze groepen vast liggen lijkt me dat geeneens een slecht idee, maar dat terzijde

Het snelste is om in PHP alle lokatie-data op te halen in een array en hier mee aan de slag te gaan. Je zorgt dan eerst dat je weet op welk lokatie-id er gezocht wordt en loopt vervolgens lekker recursief door je array totdat je all relevante lokatie-id's weet. De angst voor CPU-cycles en mem-gebruik lijken mij ongegrond. Queries zijn veel vaker de bottleneck in scripts omdat er disk-acces (traag) voor nodig is...

Regeren is vooruitschuiven


  • NMe
  • Registratie: Februari 2004
  • Laatst online: 21:24

NMe

Quia Ego Sic Dico.

Ik ben het eens met T-MOB, maar ik wil nog eens extra benadrukken dat je je datamodel beter kan omgooien om elke 'schaal' in een aparte tabel te zetten. Op die manier kun je relatief veel eenvoudigere queries maken, die ook nog eens minder data teruggeven, waardoor de overhead en daarmee de serverbelasting een stuk lager zal liggen. Ik zou dit zeker in overweging nemen. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Verwijderd

http://www.sitepoint.com/...rarchical-data-database/2
Dit systeem is daar ideaal voor. (Pagina werkt hier niet in FF, alleen in IE :?)

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Verwijderd schreef op maandag 29 november 2004 @ 06:47:
http://www.sitepoint.com/...rarchical-data-database/2
Dit systeem is daar ideaal voor. (Pagina werkt hier niet in FF, alleen in IE :?)
Pagina doet het prima in mijn FF. Maar echt ideaal is het systeem niet altijd door de forse hoeveelheid werk die nodig is om simpele wijzigingen aan te brengen.
Ik heb geregeld een stuk tekst over verschillende hierarchische systemen getikt. Zoek op "nested set" met mij als poster en je zou er wel een aantal tegen moeten komen :)

O.a. deze: [rml]ACM in "[ mssql] zoeken in nested categorieen"[/rml]
en deze: [rml]ACM in "[ PHP/MySQL] Teveel queries bij recursiev..."[/rml]

Erg interessant leeswerk voor dit probleem is trouwens het boek "Trees and hierarchies" van Joe Celko (de bedenker van het systeem dat Cheatah naar verwijst).

  • MisterData
  • Registratie: September 2001
  • Laatst online: 16-05 23:29
Celko tree is inderdaad heel erg handig in dit geval om *alle* nodes onder een bepaalde node (zoals Kalverstraat) te SELECT'en. Waar je wel op moet letten is dat je met Celko enorm veel tijd kwijt bent bij een UPDATE, dus het hangt van je systeem af... als er maar een paar keer iets veranderd wordt en het gros van de queries is SELECT, dan kun je perfect Celko gebruiken :) Zorg er wel voor dat je (zeker tijdens het testen) de ligt_in er ook nog bij hebt, want aan de hand daarvan zou je eventueel de Celko-tree kunnen opbouwen (op verzoek kan ik die tree build-code uit m'n CMS halen en hier laten zien) :)

  • dvvelzen
  • Registratie: Februari 2002
  • Laatst online: 07-08-2025
hier heb je een heel simpel voorbeeld, maar performant is het volgens mij niet echt...

select l0.naam as 'land'
, l1.naam as 'prov'
, l2.naam as 'gemeente'
, l3.naam as 'plaats'
, l4.naam as 'buurt'
, l5.naam as 'stad'
from lokaties l0
join lokaties l1 on l0.id = l1.ligt_in
join lokaties l2 on l1.id = l2.ligt_in
join lokaties l3 on l2.id = l3.ligt_in
join lokaties l4 on l3.id = l4.ligt_in
join lokaties l5 on l4.id = l5.ligt_in
where l3.naam = 'Amsterdam'
Pagina: 1