---
title: 'Uncover N+1 Queries Hidden behind (external) Library APIs!'
source: 'https://youtube.com/watch?v=3jVptc8iktk'
video_id: '3jVptc8iktk'
date: 2026-08-03
duration_sec: 462
---

# Uncover N+1 Queries Hidden behind (external) Library APIs!

> Source: [Uncover N+1 Queries Hidden behind (external) Library APIs!](https://youtube.com/watch?v=3jVptc8iktk)

## Summary

This video by Benjamin, a PHP performance expert, addresses the N+1 query problem, specifically when it's hidden behind third-party APIs. Using a real-world example from the Frosh platform's share basket module, he demonstrates how a method name like 'add' can mislead developers into inefficiently calling an API in a loop, causing repeated database queries. He shows how profiling with Tideways reveals the issue and how a simple refactor—calling the API once with all items—dramatically improves performance.

### Key Points

- **Introduction to N+1 Problem** [00:01] — Benjamin introduces the topic of performance bottlenecks in PHP, focusing on N+1 queries hidden behind third-party APIs and how method naming can lead to wrong performance assumptions.
- **Classic N+1 Example** [00:29] — Shows a simple N+1: a query for recent articles, then a loop executing a query per article to fetch the author. Uses SQLite user-defined function to slow down queries for profiling.
- **Hiding N+1 Behind Layers** [01:28] — Explains that in real code, layers between raw queries can hide N+1 problems. Recommends using a PHP profiler like Tideways to detect them.
- **Profiling with Tideways** [01:42] — Benjamin uses Tideways, a profiler his team wrote, because it has SQL query profiling and N+1 detection built in.
- **Code Walkthrough: Frosh Bundle** [01:57] — Steps through the controller: loadCart calls addLineItems, which calls addProduct, which calls CartService->add(). This switches from the Frosh bundle to Shopware core API.
- **CartService->add() Does More Than Expected** [02:41] — The add() method calls addItemRoot(), calculates, and saves the cart to the database. The API can handle multiple items, but the Frosh bundle calls it in a loop, causing inefficiency.
- **Real-World Case: Share Basket** [03:42] — In a customer consulting, they found the Frosh share basket module used for large orders with hundreds of line items. Reproducing with a demo store of six items, profiling showed repeated SQL queries (insert cart, select product) – an N+1 problem.
- **Refactor: Call API Once** [05:27] — Benjamin refactored the code to call CartService->add() only once for all line items, saving the cart and calculating only once. This reduced database operations and improved performance by 3.5 seconds for the customer.
- **Performance Improvement Demonstrated** [06:10] — After refactoring, the demo store request was 400ms faster, with cart service add and calculation called only once, and queries no longer in N+1 fashion.

### Conclusion

Third-party APIs can hide N+1 query problems behind their method names, leading to inefficient code. Profiling with tools like Tideways reveals these issues, and refactoring to call APIs once with all data can yield significant performance gains.

## Transcript

performance bottlenecks in PHP applications. And in this video, I want to cover one special case where a third-party API hides the N plus1 query and when naming of methods could lead to wrong assumptions with respect to
performance. Mo, I am Benjamin and I'm working on PHP performance topics for the last 10 years, helping thousands of developers along the way. But let's back up a little bit. What is an N plus1 performance bottleneck? The simplest
case in PHP code is something you have probably all seen. A single database query directly in the code first then a loop around the results and each loop the iteration runs another database query just changing the parameters. So
looking at this case here we see select over articles the the recent 10 articles and then we are executing a query here against the users table with the author
ID from this articles table. Uh one thing you will notice here um I added SQLite userdefined function to slow down this query we um so that we can see this um in a profiler easier. This code is purposely simplified to show the point
about N plus1 performance bottlenecks. And in your code, you probably have various degrees of layers between this raw database queries. But this video is raw database queries. But this video is especially about uh hiding N plus1
queries behind these layers. So we will see later what the problem is. You can use a PHP profiler to see the effects of N plus1 queries on performance. And you profilers in the description of this video. In this video, I will use
tideways as that is the profiler my team and I wrote and because it has SQL query profiling and one N plus1 detection built in. Let's look at the code what's happening here. So I opened the controller um the load card method
controller um the load card method and going to step through that. So load card calls add line items and then what at line item is doing it's calling add product
and what add product doing is it's calling card service add and this switches from the the fro bundle to a service card
services on shopware itself. So for the authors of the Froch bundle, it's now sort of a switch from their API to a third party API, the Shopware core. And what is the card service at method doing? And that it's the one that's um
can sort of like lead to conf uh confusion. It calls at item root at and then let's go to the concrete implementation here.
the cart. And what it's doing then it's also calculating something again and then saving the card. So the at method also saves the card into the database. And one thing that we can see is if we
go back to the cart service here then we can see the API is built in such a way that it can work with just a single item but it's also perfectly fine to work with multiple items. So the crossover between the third party API to the uh
the own API to the third party API um sort of made a small mistake where they sort of used the inefficient way of doing it uh inside a loop calling this over and over again instead of using the more efficient approach. So you're
probably asking yourself how does this relate to third party APIs and N plus1 queries in them. In a recent customer consulting, we looked at this Fro platform share basket uh module and it was used um in in the customer store. It
allows uh users of the store to share baskets with each other and they used it baskets with each other and they used it to share like really big orders of hundreds of line items and very uh complex calculations.
And if you um sort of reproduce this uh this is a demo store that I set up this is a demo store that I set up myself with six items and um I run the profiler to find out what's happening here. So what I'm doing in tideways I
click on trigger trace. I generate sort of a um token here for me to append to the URL. Um so this is a shortlived token to
generate profiling information with sort of a secret key and then going back uh on the my core graphs list um it generates a call graph for me I can see this call graph it's much uh more complex than the one we saw before and
specifically what we can see here is this section of the code calling the share basket controller this is from the fro um module that I showed you um performing operations over and over again. So cart service add card
calculate and then we can see in pink the SQL queries being repeated here insert card multiple times selecting the product multiple times. So this is a sort of n plus1 uh problem that is happening here. So I refactored this and
uh opened a pull request to only call the card service at method once for all the shared line items. And uh let's look at the code a little bit. So if you at the code a little bit. So if you remember uh the at line item method um
called add product and this one added it to the cart already. What the change code now does is it keeps the product here, attaches this to the line item and then at the end of this method at line items, it adds all the line items at
items, it adds all the line items at once. And um this leads to the cart only be saved once. Also, the card calculation only being done once. And this reduces the amount of um sort of like database operations quite a lot.
Makes the performance much faster. And uh in this pull request I also showed um this um sort of comparison between the old and the new way for this customer where this change alone improved the performance by 3.5 seconds in their
case. So let's go back to our simple demo store and uh generate the profiling demo store and uh generate the profiling data again. So another core graph token for me here. I adjust the URL. I go back to this screen
waiting for the results. So we have it here. You already see it's much faster than the uh request before. It's 400 milliseconds less. And we can see card service at only called once. Calculator is only called once. And also the
queries here are not executed really um in sort of like n plus1 fashion anymore. Instead um they are only done once. Um and it's like uh way more efficient this way. So this was a quick demonstration
way. So this was a quick demonstration of how u a third party API sort of can hide it its internals in a way that it makes N plus1's queries quite simple for makes N plus1's queries quite simple for users to make and uh where sort of like
how big an improvement can be to refactor this away um and make sure that the queries are only executed a single time. If you like this type of PHP performance content, I would be really happy if you subscribe to this channel
or click the link in the description to our newsletter. And I hope to see you our newsletter. And I hope to see you soon. Bye.
