Ik heb een relatief simpele tabel met miljoenen rijen. Voor mijn probleem zijn in feite 2 kolommen relevant: een integer foreign key categoryId en een integer timestamp. De timestamps zijn gewoon UNIX timestamps en lopen altijd op naarmate rijen worden toegevoegd aan de tabel.
De data die ik wil opvragen is: de laatste 500 rijen met categoriën die voorkomen in een lijst van meerdere categoryId's. De SQL query is dus alsvolgt:
Verder heb ik gewoon een index op (categoryId ASC, timestamp ASC), en ter indicatie, zonder LIMIT zouden iets van 10% van de resultaten uit de tabel (dus in de orde van grootte van 100.000en rijen) geretourneerd worden.
Het probleem zit 'm in die ORDER BY. Als ik die weghaal is de query gewoon vlot, zoals je zult verwachten. Ook bij het ophalen van de laatste X rijen van een specifieke categoryId is gewoon snel. De index doet bij deze twee usecases dus gewoon waarvoor het gemaakt is. Maar bij het ophalen van meerdere categoryId's kan hij de sortering zelf logischerwijs niet meer uit de index halen en past hij dus wat MySQL een "filesort" noemt toe op het resultaat, met als gevolg dat de query tot tientallen seconden kan duren. Idealiter wil ik dat ie er maar max 2 seconden over doet.
Nou heb ik best wel wat kennis van de achterliggende algoritmiek, maar niet zo heel veel van relationele databases
. Ik vind het niet heel vreemd dat domweg het ophalen van alle records en dan vervolgens de sortering toepassen een trage operatie is. Het is echter wel een beetje een domme implementatie. Feitelijk zou hij van elke categoryId snel de laatste 500 rijen goed gesorteerd uit de index kunnen halen en die dan vervolgens gaan sorteren met een merge sort tot je uiteindelijk het gewenste aantal hebt bereikt. Ik zou het in code ook zo op kunnen lossen, maar ergens is het jammer dat ik dan nog wel 500*N resultaten op moet halen.
Ik vraag me dan ook af of het niet op een of andere manier gewoon in de database opgelost kan worden.
De data die ik wil opvragen is: de laatste 500 rijen met categoriën die voorkomen in een lijst van meerdere categoryId's. De SQL query is dus alsvolgt:
SQL:
1
2
3
4
| SELECT * FROM tabel WHERE categoryId IN (/* lijst met N categoryId's */) ORDER BY timestamp DESC LIMIT 500 |
Verder heb ik gewoon een index op (categoryId ASC, timestamp ASC), en ter indicatie, zonder LIMIT zouden iets van 10% van de resultaten uit de tabel (dus in de orde van grootte van 100.000en rijen) geretourneerd worden.
Het probleem zit 'm in die ORDER BY. Als ik die weghaal is de query gewoon vlot, zoals je zult verwachten. Ook bij het ophalen van de laatste X rijen van een specifieke categoryId is gewoon snel. De index doet bij deze twee usecases dus gewoon waarvoor het gemaakt is. Maar bij het ophalen van meerdere categoryId's kan hij de sortering zelf logischerwijs niet meer uit de index halen en past hij dus wat MySQL een "filesort" noemt toe op het resultaat, met als gevolg dat de query tot tientallen seconden kan duren. Idealiter wil ik dat ie er maar max 2 seconden over doet.
Nou heb ik best wel wat kennis van de achterliggende algoritmiek, maar niet zo heel veel van relationele databases
Ik vraag me dan ook af of het niet op een of andere manier gewoon in de database opgelost kan worden.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.