Over the course of time, the performance of the Laravel importer routine gradually decreases

I have a process that retrieves data from a web service and saves it in my database. This data consists of over 20,000 items. In order to save them into the database, I need to gather some information first before storing them. Therefore, I have a foreach loop that runs over 20,000 times, executing a read and write operation for each item.

However, as time passes, this method starts to slow down significantly. It now takes more than an hour to complete!

I attempted to improve performance by disabling the query log (DB::disableQueryLog()), but there was no noticeable enhancement.

This is part of the code I am using:

$data = API::getItems();

foreach ($data as $item) {
    $otherItem = OtherItem::where('something', $item['something'])->first();
    if (!is_null($otherItem)) {
        Item::create([
            ...
        ]);
    }
}

To address this issue, I decided to preload all OtherItem into a collection, which resolved the slowdown problem:

$data = API::getItems();

$otherItems = OtherItem::all();

foreach ($data as $item) {
    $otherItem = otherItems->where('something', $item['something'])->first();
    if (!is_null($otherItem)) {
        Item::create([
            ...
        ]);
    }
}

Nevertheless, I am seeking to comprehend why the initial approach deteriorated in performance over time and what is the optimal way to handle such tasks going forward.

EDIT:

In order to clarify: I am aware that performing 20,000 queries is not efficient and, under normal circumstances, performance may not be crucial (unless the task takes hours instead of minutes). Currently, I will only run this routine occasionally while in development. Ultimately, I combined both solutions provided (adding batching and buffering the items). Here is the revised code for reference:

$data = collect(API::getPrices());
$chunks = $data->chunk(500);

$otherItems = OtherItem::all();

foreach ($chunks as $items) {
    $buffer = [];
    foreach ($items as $item) {
        $otherItem = otherItems->where('something', $item['something'])->first();
        if (!is_null($otherItem)) {
            $buffer[] = [
                ...
            ];
        }
    }
    Item::insert($buffer);
}

Thus, I am puzzled regarding the substantial slowness of the process (even with all the queries optimized). To delve deeper into this matter, I have initiated benchmarking. When utilizing the two-query approach, the following results were obtained:

For 6000 iterations:

  • Max read: 11.5232 s
  • Min read: 0.0044 s
  • Mean read: 0.3196 s

  • Max write: 0.9133 s

  • Min write: 0.0007 s
  • Mean write: 0.0085 s

Every 10-20 iterations, the read time unexpectedly spikes to over a second for 2-3 iterations, without clear reason as to why.

As an additional curiosity, I also performed benchmarking to compare the difference between chunking and buffering the items before inserting them into the database:

  • without buffering: 1,115.4 s (18 min 35 s)
  • chunking and buffering: 1064.7 s (17 min 45 s)

Answer №1

The initial block of code generates a total of 40000 queries for 20000 items, resulting in two queries per item - one to retrieve the data and another to store something.

On the other hand, the second code snippet produces 20001 query and also performs poorly.

An efficient solution involves creating an array and utilizing the insert() function instead of repeatedly using the create() method whenever data needs to be stored. By following this approach, only 2 queries will be executed instead of the original 40000 and 20001.

$otherItems = OtherItem::all();
$items = [];

foreach ($data as $item) {
    $otherItem = $otherItems->where('something', $item['something'])->first();
    if (!is_null($model)) {
        $items[] = [.....];
    }
}

Item::insert($items);

Answer №2

To address the issue of slow down, it is important to understand that the bottleneck lies in the numerous queries being made, each requiring a round trip to the database.

One effective strategy to mitigate this problem is by chunking the inserts using database transactions. By experimenting with different batch sizes, such as inserting a few hundred records at a time, you can optimize the process.

Here's how you can implement this technique:

  • Start a transaction
  • Loop over a chunk of data and perform the inserts
  • Commit the changes
  • Repeat this process for each chunk until all data is inserted

Laravel's ORM offers a handy chunk method specifically designed for this purpose.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Failure to receive an array as the output after invoking a web service using AJAX-JSON

I am working on retrieving data from my web service in array format so that I can loop through and fetch all the necessary information. Here's what I have done so far: When I return the result in my web service, I use return json_encode($newFiles); ...

Is it possible for me to send JSON data using a form to HTTP_RAW_POST_DATA?

Currently, I am in the process of creating a web interface for code that is typically designed to run on Android devices. I transmit JSON data and retrieve the data by using the following method: $json = json_decode($HTTP_RAW_POST_DATA,true); Is there a ...

PHP Ajax Image Uploading and Storage

Is there a way to effortlessly upload an image and save it in the uploads folder without any page refresh? Not only that, but can we also have the uploaded image displayed on the screen within a designated div section? Unfortunately, I seem to encounter a ...

What is the process for adding dates chosen from dropdown menus into a mySQL table using PHP?

Is there a way to insert the selected date and time from 5 dropdowns (Y, m,d, H,i) into a mySQL table as a datetime using PHP5? To combine the values into a string: $DateTime="$Year-$Month-$Day $Hour:$Minute:00"; You can then use strtotime function: $D ...

What is the best approach to determine the numerical equivalents of options in a dropdown menu using PHP and JS

Hey guys, I'm really stuck on this problem and I can't seem to find a helpful tutorial anywhere. I've got a form with two drop-down menus, each with a "value" attribute. What I want is for users to be able to select an item from both drop-do ...

HTML counterpart to PHP's include for JavaScript components

I am searching for a Javascript alternative to a method I have been using in PHP. Specifically, I want to streamline the basic setup of my pages: <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

Utilizing PHP and jQuery to dynamically populate Google Maps with multiple markers

I am currently working on integrating a Google map with a database to dynamically display multiple markers using PHP and MySQL. Below is the code I have been using: <?php //This section retrieves data from the database for later use in jQuery //CREATE ...

Rule for identification in the .htaccess file

Is it possible to globally rewrite URLs with GET variables instead of targeting specific files? Transforming http://example.com/{something}?id=1 To: http://example.com/{something}/id/1 Or even without using the word id: http://example.com/{something} ...

Place a div element immediately following a table row in the HTML document

Welcome to my hotel and cabin availability page! I've created a PHP query that displays the available hotels and cabins in a table format. However, I want to enhance the user experience by displaying a Google Maps location and some pictures of each ho ...

Retrieving Mysql field data from an array

I have a script designed to showcase files within a specific directory: <?PHP # Defining the current directory $directory = dir("./"); # Uncomment this line if you wish to activate Extension Filter: $allowed_ext = array(".deb", ".ext", ".ext", ".ext" ...

What techniques can be used to streamline this regex and eliminate the need for recursion?

Regex: (?|`(?>[^`\\]|\\.|``)*`|'(?>[^'\\]|\\.|'')*'|"(?>[^"\\]|\\.|"")*"|(\?{1,2})|(:{1,2})([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)) ...

Customizing Your WordPress Menu with HTML5 Features

Can someone assist me in creating a customized WordPress menu? I am facing issues with unnecessary classes added by WordPress and the lack of certain attributes on dropdowns. Below is the HTML code: <nav class="navbar navbar-default navbar-static- ...

standard pregmatch when using preg_split

Can someone help me understand how to use preg_match effectively? /\s*;\s*/ For example: preg_split('/\s*;\s*/', $something); I'm struggling with understanding how to replace preg_split. I am unsure of the meaning of ...

Can changes on a webpage in PHP be saved without needing to be sent to a database?

I've been conducting some research on this matter, but I haven't been able to find a solution. Is it feasible in PHP to save modifications made on a webpage without storing the information in a database? I want to empower users to edit their pag ...

What is the best way to assign a unique query ID from a MySQL table using a global variable?

I am a beginner in MySQL and have a query. For my new application, I have used Nodejs and the MySQL module to connect to my database. I need to query using a specific variable and retrieve tables with similar columns. Below is my code: var sm = "salam" ...

Reduce the file size of and store base64-encoded images

My application is currently handling base64-encoded image files received from a web browser. The goal is to save these images on the client-side, and I've successfully achieved this with the following code: $data = base64_decode($base64img); $fileNam ...

Is it possible to limit PHP variables to only accept specific types of values?

I'm curious if it's possible in PHP to restrict a variable to only accept certain types of values that it is defined for. For example, in C#: public int variable = 20; public string variable2 = "Hello World"; So how would this work in PHP if I ...

Struggling with converting blob file to an image within a NextJS application using data from a MySQL database

Currently, I am in the process of working on a project where I need to retrieve an image stored as a blob file in my database. However, for some reason, the image is not displaying properly. Here is the code snippet from the first file, products.jsx: impo ...

Retrieve the range of dates starting from the day of birth

I am currently working on developing a peers page for my website. I need assistance in creating a query that can retrieve users from the users table, which is organized as id, name, gender, dob. The query should fetch users based on their date of birth i ...

Sorting arrays of x and y coordinates in either JavaScript or PHP is a common task

Utilizing JSON data, I successfully populated a highcharts graph with the following format: [[x,y],[x,y],[x,y],[x,y]] The data is arranged by the x value initially, as the file receives an unordered list of numbers and then tallies the frequency of each n ...