We are currently working on a very interesting system which is a digital Sommelier service. With complex formulas built by professional sommeliers we match dishes and wines, and we’ve built mobile apps to allow people in restaurants, shops or at home to see which wines match dishes they would like to combine.

To match dishes and wines we run a Laravel command as a cron job every night which runs formulas to calculate pairing score between a dish and a wine. The command needs to go through hundreds of items and run formulas on them.

I’ll avoid going into too much detail about the project and get straight to the steps we took to significantly improve one functionality of the system.

The two Laravel models we have are as follows:

Dish with table “dishes” and a lot of properties

Vintage (single year of a wine) with table “vintages” and also a lot of properties

There’s a “many to many” relationship between these two with table “pairing_vintages_dishes” which also contains score for each dish -> wine pairing.

The first iteration of the command we built (in a hurry I might add) did a pretty straightforward thing:

Fetch all Dishes

Fetch all Vintages

For every Dish, go through every Vintage and run formulas. There are several formulas here comparing multiple attributes of a Dish object to multiple attributes of a Vintage object. After running these formulas we run Laravel’s sync() function to save the score for all the related Vintages.

(The command didn’t actually go through all the objects, it compared only those which were changed during the day. But this still happened to be a lot of objects.)

The command worked, but very slowly. We left it working like that for some time until we finished critical stuff in the system and had time to go back and refactor some slow running code.