Om du funderar lite på hur frågan är upplagd (och måste vara upplagd med nuvarande DB-struktur) så inser du att allt måste matchas mot allt, så att säga, innan svaret på frågan kan beräknas.
Den första saken du skulle kunna göra är att bara räkna ut rekommenderade produkter för en viss vara en gång per (tidsperiod) och cacha detta värde. Och när (tidsperiod) har passerat, beräkna värdet igen. Detta är dock bara en temporär lösning som inte löser det grundläggande problemet.
Ett bättre sätt är nog att skapa en relationstabell mellan tbl_products och sig själv där du har en räknare som du räknar upp varje gång för varje försäljning av två varor ihop. Då måste du uppdatera detta för varje order som går igenom. Sedan blir frågan för att hämta ut rekommenderade produkter betydligt snabbare.
Alltså har du fälten productid1, productid2, och buy_count
Du bör definiera att productid1 > productid2. Detta kontrollerar du vid inmatning. Om en rad inte existerar, skapa den, annars inkrementera räknaren.
Minneskomplexiteten är O(n^2). Dvs, om du har 100 produkter, och alla produkter säljs tillsammans med alla produkter kommer du få 100*100=10000 rader i den tabellen.
