Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Pciranda's avatar

Too many placeholders

Good afternoon.

I have a problem entering a large amount of data ... +10 million rows.

The process itself is simple.

  1. Read the file.
  2. Validate each line.
  3. Insert valid rows in the database.

But when I try to insert this large amount. I get the following error.

Illuminate \ Database \ QueryException: SQLSTATE [HY000]: General error: 1390 Prepared statement contains too many Placeholders
at api / vendor / laravel / framework / src / Illuminate / Database / Connection.php: 664
     660 | // If an exception occurs when attempting to run a query, we'll format the error
     661 | // message to include bindings with SQL, which will make this exception a
     662 | // lot more helpful to the developer instead of just the database's errors.
     663 | catch (Exception $ e) {
   > 664 | throw new QueryException (
     665 | $ query, $ this-> prepareBindings ($ bindings), $ and
     666 | );
     667 | }
     668 |
0 likes
8 replies
siangboon's avatar

the error message "Prepared statement contains too many Placeholders" is clear, the values you provide in the query is less than the placeholders or does not match....

1 like
Pciranda's avatar

Thx SIANGBOON.

Yep ...

The file in question has a total of 18 columns. Considering the placeholder limit: 65536/18 = 3640,888 ... I can insert 3640 lines.

So I tried ...

// $header is a collection of column names;
// $data is a collection of lines from the file;
$cols = $header->count();
    
$limit = 65000; // Mysql placeholder limit ...
        
$data
    ->chunk( floor($limit / $cols) )
    ->each(function($calls) {
        \App\ Models\Call::insert($calls);
    });

it works. but ... now I have 3,296 querys. each with 3611 rows. 😅

any tips to increase this mysql placeholder limit? if possible...

4 likes
Snapey's avatar

Chunking a few thousand at a time is probably best. If you do more, you just spend more time juggling large amounts of data in memory, and probably does not speed it up any.

probably turn indexing off and build indexes later.

You are not having to check for duplicates are you?

1 like
jlrdw's avatar

You have a table with more than 65,536 fields?

Or

Does your number of question marks (placeholders) not match the number of parameters you have.

Pciranda's avatar

The insertion is done on top of a temporary table (without indexing). After validation of the coordinator, the temporary table is inserted in the calls table and droped at the end of the process.

This database receives information from various telecommunications service providers.

The exchange of information is sometimes by api, direct query to third party db or files: csv, tsv, xls, json or xml.

<results feeder_id = "XXXX">
    <contact status = "success" queue = "XXXXXXXX" id = "3646">
        <number 
               answered_at = "28/05/2019 08:56:56"
               destination = "XXXXXXXXXX"
               duration = "127"
               callfilename = "1559044588.67525160.WAV"
               hangup_at = "28/05/2019 08:59:02"
               id = " 2889 "
               dialed_at =" 28/05/2019 08:56:28 "> 
               16
        </number>
  </contact>
  ... +10 million contacts or even more per file
</results>

This is one of the file types we receive. Asterisk Based (Asterisk.org) After importing we perform aggregate functions for management reports and make them available as a centralized query.

The biggest problem is the volume of data ..

Pciranda's avatar

JLRDW,

The number of question marks is greater than the 65536 (2¹) limit. Then MySql throws an error 1390.

Just to get a sense: 1 of the files has 18 columns and 10 million more rows.

1 file x 18 columns x 10 rows = 180,000,000 question marks.

The work around was to divide the data and insert according to the limit.

6500 placeholders / 18 columns = 3611 rows per query

as I mentioned earlier.

Pciranda's avatar

Updating.

I found this in the php documentation.

PDO :: ATTR_EMULATE_PREPARES Enables or disables emulation of prepared statements. Some drivers from not support native prepared statements or have limited support for them. Use this setting to force PDO to either always emulate prepared statements (if TRUE and emulated preparations are supported by the driver), or to try to use native prepared statements (if FALSE). It will always fall back to emulating the prepared statement if the driver cannot successfully prepare the current query. Requires bool.

https://www.php.net/manual/en/pdo.setattribute.php

So..

// it's the same instance.
DB::connection()->getPdo() === (new App\Models\Call)->getConnection()->getPdo(); // true

// set TRUE;
DB::connection()->getPdo()->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

App\Models\Call::insert($data);

// set FALSE
DB::connection()->getPdo()->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

It works!

now benchmarking.

3 likes

Please or to participate in this conversation.