mboost-dp1
"Simpel" mange til mange relation
- Forside
- ⟨
- Forum
- ⟨
- Programmering
Hej mednørder, nu har det her problem irriteret mig det meste af en dag:
Jeg har et simpelt tagging system, hvor man skal kunne søge på entities der har alle søgeord tilknyttet (layout).
Umiddelbart en simpel søgning, indtil det går op for en at en join giver alle rows fra Doc tabellen der blot har ét eller flere søgeord.
Næste forsøg bliver en inner join på en inner join på en (.. se eksemple her ..) hvilket en MySQL server har det fint med, indtil man laver et par hundredtusinde relationer og søger på en femten - tyve ord :-/
Er der nogen der har en idé til hvordan man løser dette problem? Har været det meste af google igennem, og umiddelbart er jeg ikke den eneste der har dette problem :-/
Jeg har et simpelt tagging system, hvor man skal kunne søge på entities der har alle søgeord tilknyttet (layout).
Umiddelbart en simpel søgning, indtil det går op for en at en join giver alle rows fra Doc tabellen der blot har ét eller flere søgeord.
Næste forsøg bliver en inner join på en inner join på en (.. se eksemple her ..) hvilket en MySQL server har det fint med, indtil man laver et par hundredtusinde relationer og søger på en femten - tyve ord :-/
Er der nogen der har en idé til hvordan man løser dette problem? Har været det meste af google igennem, og umiddelbart er jeg ikke den eneste der har dette problem :-/
Jeg har ikke så stor erfaring med MySQL, så jeg ved ikke om det samme kan lade sig gøre der, men hvis jeg havde samme problem på en SQL Server, så ville jeg forsøge mig med at lave et indexed view, altså et view på Doc-Rel-Tag relationen og et indeks på Doc.Content og Tag.Tag attributterne.
Indexet ville fylde en hel del på disken, men ville spare en masse tid på dit lookup da du ville kunne undvære at joine alle data for hver query og kun gøre det når indexet bliver oprettet eller opdateret.
Indexet ville fylde en hel del på disken, men ville spare en masse tid på dit lookup da du ville kunne undvære at joine alle data for hver query og kun gøre det når indexet bliver oprettet eller opdateret.
SELECT d.*
FROM Rel r, Doc d, Tag t
WHERE r.TagId = t.TagId
AND (t.Tag IN ('ord1', 'ord2', 'ord3'))
AND d.ID = r.DocID
GROUP BY d.ID
HAVING COUNT( d.ID )=3
Ved ikke om det virker sådan? Fandt bare hurtigt et eksempel og omskrev det til dine navne (håber at jeg fik ændret dem rigtigt).
Kig her, på "Toxi":
http://www.pui.ch/phred/archives/2005/04/tags-data...
Dj Mortar:
En Propel udvikler anbefalede denne:
Dette giver desværre en del flere joins, men tilgengæld kan man optimere koden, så de tokens der er færrest dokumenter der har kommer først, og derved reducere antallet af opslag betragteligt.
I din løsning er det desuden en fordel at ændre
til
herved kan man også bruge wildcard søgninger (fx. vil en søgning på 'data%' og 'database' fejle uden '>').
@arne_v:
Yep, der er index på alle primær nøgler og foreignkeys
Og jeg siger mange tak til jer alle. Næste gang vælger jeg en DB der kan lave INTERSECT :-)
En Propel udvikler anbefalede denne:
$tblAlias = self::getRndTblAlias();
$sql .= 'SELECT DISTINCT '.$tblAlias.'.DocumentId FROM'."\n";
foreach ($tokens as $token) {
$token = mysql_real_escape_string($token);
if ($firstToken) {
$sql .= '(SELECT DocumentId FROM Support_Document_Tag JOIN (SELECT Id FROM Support_Tag WHERE Tag LIKE \''.$token.'\') Tags ON Tags.Id = TagId) '.$tblAlias."\n";
$firtToken = false;
} else {
$tblAliasPrev = $tblAlias;
$tblAlias = self::getRndTblAlias();
$sql .= 'JOIN (SELECT DocumentId FROM Support_Document_Tag JOIN (SELECT Id FROM Support_Tag WHERE Tag LIKE \''.$token.'\') Tags ON Tags.Id = TagId) '.$tblAlias.' ON '.$tblAlias.'.DocumentId = '.$tblAliasPrev . '.DocumentId' . "\n";
}
}
Dette giver desværre en del flere joins, men tilgengæld kan man optimere koden, så de tokens der er færrest dokumenter der har kommer først, og derved reducere antallet af opslag betragteligt.
I din løsning er det desuden en fordel at ændre
HAVING COUNT( d.ID )=3
til
HAVING COUNT( d.ID ) >= 3
herved kan man også bruge wildcard søgninger (fx. vil en søgning på 'data%' og 'database' fejle uden '>').
@arne_v:
Yep, der er index på alle primær nøgler og foreignkeys
Og jeg siger mange tak til jer alle. Næste gang vælger jeg en DB der kan lave INTERSECT :-)
Gå til top
Opret dig som bruger i dag
Det er gratis, og du binder dig ikke til noget.
Når du er oprettet som bruger, får du adgang til en lang række af sidens andre muligheder, såsom at udforme siden efter eget ønske og deltage i diskussionerne.