Avatar billede fireburner Nybegynder
07. november 2007 - 14:13 Der er 8 kommentarer og
1 løsning

Avanceret søgning

Hej!

Jeg er ved at lave en avanceret bruger søgning, som jeg gerne vil lave så effektiv som muligt.

For at simplificere det kan vi sige, at man kan søge på:
- køn (0 = hunkøn,1 = hankøn,2 = par)
- alder (0->99)
- bopæl (0 = jylland, 1 = fyn, 2 = sjælland)

Jeg ville altså lave tabellerne således (igen simplificeret):

tableUsers
- idUser
- strUsername

tableGenderToUsers
- idGender
- ridUser

tableAgeToUsers
- idAge
- ridUser

tableAreaToUsers
- idArea
- ridUser

Det er muligt at vælge f.eks. alle aldersgrupper, men kun søge efter folk i odense - hvilket gør det temmeligt ubrugeligt blot at lave en enkelt table med indexes. Derfor har jeg lavet index-tabellerne.

Mit spørgsmål er så - hvordan ville en effektiv SELECT sætning se ud, hvis man f.eks. ville hente:
- Alle brugere fra FYN med en alder mellem 20 og 60
- Alle HUNKØN i JYLLAND

Jeg har leget lidt med ideen om at lave en SQL sætning således:
SELECT tableUsers.* FROM tableUsers WHERE idUser IN(SELECT ridUser FROM tableGenderToUsers WHERE idGender = 2 AND ridUser IN(SELECT ridUser FROM tableAreaToUsers WHERE idArea IN(1,2)))

Men det ser blot ud til at dette databaseopslag er enormt langsomt, og en explain sætning viser da også at det langt fra er effektivt...

There - undskyld den lange stil - og jeg håber der er nogle der kan / vil hjælpe! Tusind tak :)
Avatar billede fennec Nybegynder
07. november 2007 - 14:17 #1
Det virker som en meget indviklet DB opbygning. Det er meget bedre at smide det i en tabel:

tableUsers
- idUser
- strUsername
- idGender
- idAge
- idArea
Avatar billede fireburner Nybegynder
07. november 2007 - 14:21 #2
hej fennec

Og tak for dit svar

Det er også sådan jeg normaltvis ville have gjort det, men eftersom jeg ikke kan lave et effektivt index på den opbygning (da man f.eks. i en søgning ikke ville vælge at idGender skal være noget bestemt), er den ikke helt god... Du skal forestille dig at der kan være 100.000 brugere f.eks., og 20 forskellige søge kriterier.. Så en alm. sætning uden indexes ville tage for lang tid at afvikle.
Avatar billede fennec Nybegynder
07. november 2007 - 14:55 #3
Ved ikke hvor kraftig din server er, men den opbygning du har, kan jeg ikke se er mere effektiv. Tvært imod... Databasen har dælme mange joins den skal styre.

Desuden burde en ganske normal select på +100k rækker tage max et par sek. Og skal idGender ikke være noget bestemt, undlades den bare fra where hvilket kun forøger søgetiden.

Med min opbygning ville søgningerne se sådan ud:

select * from tableUsers where idAge>10 and idAge<20
select * from tableUsers where idAge>10 and idAge<20 and idGender=1
select * from tableUsers where idAge>10 and idAge<20 and idGender=1 and idArea=3

Alle disse 3 select ville max tage et par sek at afvikle. Selv uden indexes.

ps. Jeg ville så have et par ekstra tabeller om indeholder en reference til idGender og idArea

Area
- ID
- Area

Gender
- ID
- Gender
Avatar billede fennec Nybegynder
07. november 2007 - 14:57 #4
Vil du holde ved din nuværende opbygning (hvad jeg klart fraråder), skal jeg gerne lave et eks på opslag til dig med den opbygning.
Avatar billede fireburner Nybegynder
07. november 2007 - 15:06 #5
Hej igen

Og tak for din uddybning - jeg er dog alligevel desværre nødt til at finde en anden løsning. Selvom det max tager et par sek. at lave det opslag som du skriver, så dur det ikke - fordi hvis der er 5-10 brugere der laver en søgning i sekundet, så er der et gevaldigt problem med database serveren (det er en dating-portal der er tale om).

Min opbygning er mere effektiv, hvis man tænker med i det at tableUsers bliver meget meget stor (muligvis 1-2GB), mens index tabellerne givetvis ville fylde max 1MB pr. stk da det blot er int's der skal søges iblandt...

Jeg håber du kan se hvad jeg mener :) Tak
Avatar billede fireburner Nybegynder
07. november 2007 - 15:10 #6
Det jeg gerne vil have er sådan ca:

Alder: 20 år, køn = hunkøn, område = fyn

Så ville jeg gerne, at den første finder de brugere der er i aldersgruppen (20 år) - dvs. nu er der måske 7.000 brugere. Så skal den blandt de brugere finde hunkøn - så er der måske 3.500 brugere tilbage. Og tilsidst de fra Fyn, hvilket måske efterlader 400 brugere.

Jeg vil så kunne slå op i users tabellen og hente disse 400 brugere ud.

Søgninger som denne kan som sagt ske 10 gange i sekundet, og derfor er det så vigtigt at SQL'en er afsindigt effektiv - for hvis jeg skal løbe hele users tabellen på 2-5GB igennem hver gang der laves en søgning, så går harddisken på database serveren i knæ...
Avatar billede fennec Nybegynder
07. november 2007 - 15:15 #7
Så skal du joine:

select u.* from tableUsers u
inner join tableAgeToUsers age on age.ridUser=u.idUser and age.idAge=20
inner join tableAreaToUsers area on area.ridUser=u.idUser and area.idArea=3
inner join tableGenderToUsers gen on gen.ridUser=u.idUser and gen.idGender=1

Jeg går ud fra at idArea og idGender er en ID-henvisning til en anden tabel.
Avatar billede fireburner Nybegynder
08. november 2007 - 09:25 #8
hej fennec

Det var lige præcis det, jeg var ude efter - jeg kan se den bruger indexes i tabellerne og det kører rigtigt hurtigt!

idArea og idGender er bare henvisninger til interne PHP arrays, og altså ikke nye databaser.

Mange tak :)

Hvis du opretter et svar får du points!
Avatar billede fennec Nybegynder
08. november 2007 - 09:36 #9
.o) <-- One Eyed Jack
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester