Innan vi går in på för tidig optimering läge, kan det vara användbart att titta på följande frågemall. Om inte annat skulle detta kunna användas som en baslinje mot vilken effektiviteten av möjliga optimeringar kan mätas.
SELECT T.Tagid, TagInfo.TagName, COUNT(*)
FROM Items I
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId
JOIN ItemTagMap T ON I.ItemId = T.ItemId
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId
WHERE I.ItemId IN
(
SELECT ItemId
FROM Items
WHERE -- Some typical initial search criteria
Title LIKE 'Bug Report%' -- Or some fulltext filter instead...
AND ItemDate > '02/22/2008'
AND Status = 'C'
)
--AND T1.TagId = 'MySql'
GROUP BY T.TagId, TagInfo.TagName
ORDER BY COUNT(*) DESC
Underfrågan är "drivfrågan", dvs den som motsvarar slutanvändarens initiala kriterier. (se nedan för detaljer om hur denna fråga, som krävs flera gånger kan passa i ett övergripande optimerat flöde) Kommenterad är JOIN på T1 (och möjligen T2, T3, när flera taggar är valda), och, med WHERE-satsen, den tillhörande kriterier. Dessa behövs när användaren väljer en viss tagg, antingen som en del av den initiala sökningen eller genom förfining. (Det kan vara mer effektivt att placera dessa kopplingar och var-satser i underfrågan; mer om dessa nedan)
Diskussion... "Drivfrågan" eller en variant därav behövs för två distinkta syften:
-
1 för att tillhandahålla den fullständiga lista över ItemId som behövs för att räkna upp alla associerade taggar.
-
2 för att tillhandahålla de första N ItemId-värdena (N är visningssidans storlek), i syfte att slå upp artikeldetaljinformation i artikeltabellen.
Observera att hela listan inte behöver sorteras (eller så kan den ha nytta av att sorteras i en annan ordning), varvid den andra listan måste sorteras baserat på användarens val (säg efter datum, fallande eller efter titel, alfabetiskt stigande ). Observera också att om det finns någon sorteringsordning som krävs, kommer kostnaden för frågan att innebära att man hanterar hela listan (skygg för udda optimering av SQL själv och/eller någon denormalisering, SQL måste "se" de sista posterna på den listan , om de tillhör toppen, sorteringsmässigt).
Detta senare faktum är för att ha samma fråga för båda ändamålen, motsvarande lista kan lagras i en temporär tabell. Det allmänna flödet skulle vara att snabbt slå upp de översta N-postposterna med deras detaljer och returnera detta till applikationen på en gång. Applikationen kan sedan få ajax-mode listan över taggar för förfining. Denna lista skulle skapas med en fråga som liknar den ovan, där underfrågan ersätts med en "välj * från temporaryTable". Oddsen är goda att SQL-optimeraren kommer att bestämma sig för att sortera den här listan (i vissa fall), låt oss låta den göra det, snarare än att andra gissa det och sortera det explicit.
En annan punkt att överväga är att kanske ta med join(s) på ItemTagMap-tabellen inuti "drivfrågan" snarare än som visas ovan. Det är förmodligen bäst att göra det, både för prestanda och för att det kommer att skapa rätt lista för syftet #2 (visning av en sida med föremål).
Frågan/flödet som beskrivs ovan kommer sannolikt att skalas ganska bra, även på relativt blygsam hårdvara; preliminärt in i 1/2 miljon+ objekt, med ihållande användarsökningar kanske upp till 10 per sekund. En av nyckelfaktorerna skulle vara selektiviteten hos de initiala sökkriterierna.
Optimeringsidéer
- [Beroende på de typiska sökfallen och på datastatistiken] kan det vara meningsfullt att avnormalisera genom att föra (förvisso duplicera) några av Items fält till ItemTagMap-tabellen. Särskilt korta fält kan vara "välkomna" där.
- I takt med att data växer i fler miljoner objekt kan vi utnyttja den typiskt starka korrelationen hos vissa taggar (ex:i SO kommer PHP ofta med MySql, btw ofta utan goda skäl...), med olika knep. Till exempel kan introduktionen av "multi-Tag" TagIds göra indatalogiken lite mer komplicerad, men kan också minska kartstorleken avsevärt.
-- 'ingen sagt! --
Lämplig arkitektur och optimeringar bör väljas i ljuset av de faktiska kraven och den effektiva datastatistiska profilen...