The Solution
Apply the Haversine formula using DrizzleORM’s magical sql
operator and ensure your SQLite database has installed the math
extension (sqlean is a fantastic option for this!), if you’re using Turso, they provide this, check out the Doing it in SQLite section for more info!
|
|
You can find the full code here: https://github.com/troypoulter/fuelpulse/blob/dadd1855fac98fc60198b43d4fe6d5a19ebe1e06/app/search/page.tsx#L37-L49.
The Plot
I’ve been recently working on Fuel Pulse, an Australian fuel price tracking website, and I needed to find all the fuel stations near you. When I started, I did it the simple way of calculating it at the API layer, I didn’t know how to work this out at the DB layer yet, as I was trying out some new things: Drizzle ORM and SQLite.
Here’s a look at a small sample of the performance gains I got when shifting this calculation in the DB!
Doing it the simple but inefficient way
You can see in my pull request troypoulter/fuelpulse - #6 perf: apply Haversine formula at the DB layer instead of API layer what the code used to look like, here’s a breakdown:
- Retrieve a list of all stations from the database.
- Map through each station, calculate the distance using the Haversine formula and filter the results.
|
|
Now, the issue wasn’t whether it took a long time to run the haversineDistance
function over each station once we got them all back (that was fast). The issue was this required returning all the stations, which at the time of writing is 2,854!
This made that DB call take a lot longer than it really needed to be, coupled with wanting to also return prices for each station, I had to make a second query! You can see just how long this was taking.
But, if I could apply the formula when I make the initial DB query, I would only return the stations that are within the distance, and, get the pricing data, all at once!
I didn’t do this initially as I wanted to focus on building the core website, but after I did the initial release, I came back to this and did more research and I found the path forward!
Doing it better
The answer rests with Drizzle’s magical sql
operator, where I can mix in raw SQL alongside the type safe queries. It ended up being really neat and simple to apply! I’ve included the price
part as well to show the full query in all its beauty!
|
|
You can see in the pull request how much code I was able to remove and simplify the operations, which brought the improved speeds!
Doing it in SQLite
This part is what actually took longer to work out, as SQLite, unlike other databases, doesn’t contain the required math
functions to apply the Haversine formula by default - you need to load them in.
Say hello to sqlean, a fantastic open-source set of SQLite extensions that includes many useful functions, like math
!
Now, luckily, I use Turso to host my SQLite database, and they make it really simple to create a database with these extensions installed.
|
|
If you wanted to do it yourself, you’d need to follow the sqlean
guide on installing it for your sqlite
which I haven’t tried yet but plan to in the future!