I am inserting a lot of records to a MySQL database and I'm trying to achieve decent INSERT performance. I am using MySQL 8.0 with the MySQL Connector C++ 8.0.
In order to determine the fastest way to insert my data, I built a small test program that simply inserts 10000 records into a table. In case it helps, this is the table structure:
CREATE TABLE IF NOT EXISTS Parent (
id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY,
xxuint1 INTEGER UNSIGNED,
xxuint2 INTEGER UNSIGNED,
xxuint3 INTEGER UNSIGNED,
xxuint4 INTEGER UNSIGNED)
I created a structure with values and made an array (tblParent[10000]) of 10,000 of them filled with random numbers. Population of this array was completed before the insertions so I could measure insertion performance only. The function below is my basic Insertion function:
void InsertData(sql::Connection* con)
{
sql::PreparedStatement* pstmt = NULL;
try {
std::string sql = "INSERT INTO Parent("
"xxuint1, xxuint2, xxuint3, xxuint4"
") VALUES (?,?,?,?);";
pstmt = con->prepareStatement(sql);
for (size_t i = 0; i < NUM_PARENTS; ++i) {
pstmt->setUInt(1, tblParent[i].uint1);
pstmt->setUInt(2, tblParent[i].uint2);
pstmt->setUInt(3, tblParent[i].uint3);
pstmt->setUInt(4, tblParent[i].uint4);
pstmt->execute();
}
} catch(sql::SQLException &e) {
std::cout << "SQLException: " << e.what() << std::endl;
}
delete pstmt;
}
In general, when inserting many records, you can achieve much better performance by using multiple values lists:
INSERT INTO MyTable (col1, col2, col3) VALUES (?, ?, ?), (?, ?, ?), ... number_of_records
as opposed to inserting records one at a time. for each number of records:
INSERT INTO MyTable (col1, col2, col3) VALUES (?, ?, ?)
I was assuming that the above code would use the multiple values lists method behind the scenes, but based on my performance measurements I don't believe it is.
Here's what I got:
InsertData code with 10,000 records:
~300 records / sec.
Surrounding InsertData with "START TRANSACTION" and "COMMIT":
~8000 records / sec
If I rewrite Insert Data so that I am inserting the data from the array directly into the sql as strings, e.g.
std::string sql = "INSERT INTO Parent("
"xxuint1, xxuint2, xxint3, xxbigint4"
") VALUES (";
for (size_t i = 0; i < NUM_PARENTS; ++i) {
sql += to_string(tblParent[i].uint1) + ", ";
sql += to_string(tblParent[i].uint2) + ", ";
sql += to_string(tblParent[i].uint3) + ", ";
sql += to_string(tblParent[i].uint4) + "); ";
}
I get similar performance as above.
Performance improved when I explicitly began using the multiple values lists. I adjusted my sql to include " VALUES (?, ?, ?), (?, ?, ?), ..." and this improved performance to ~14,000 records / sec. But the best times came from converting my data to strings, and inserting that data directly into the sql, using the multiple values lists. I got up to ~40,000 records / sec doing this.
However, though the speed is fine, I don't think converting my data to text and inserting this into the sql is an ideal method. How can I optimize my insert speed and still use the pstmt->setUint() method?