How to update millions of rows quickly in mysql
Use an "Update-Select". I think it should be the fastest way to update many rows. Therefore see this question:
MySQL - UPDATE query based on SELECT Query
How to Update 1 Million of rows quickly in MYSQL
I also encountered this problem before. That was around 2009 or 2010 where I need to update multiple entries fast because of the request timeout. Some solution I found was to extend the request timeout configuration of the server but another solution I found was the create a temporary table on the database server and relate the two tables but unfortunately, I cannot share with you the link because that was a long time ago.
So here what I did as long as I could recall:
- Create a temporary table with similar structure to your CSV bearing the primary key to which relates to the table you like to perform the update. I know MySQL has the temporary table capability.
- From your CSV, upload data by insert the record at once (by batch or multiple values on INSERT statement). This will be fast
- Once you have inserted all the record, relate the temporary to your table on UPDATE statement.
- Example:
UPDATE orig_table ot, temp_table tt SET ot.URLRedirect=tt.URLRedirect WHERE ot.ID=tt.ID
- Destroy your temporary table.
The UPDATE statement will set the value of orig_table to the new value from temp_table provided that they relate through their ID.
Update about 1 million rows in MySQL table every 1 hour
Apart from the fact that your code is a little bit confusing ($PER_part2
and $PER_part3
are unused) i would do the following:
The script will not work with result_array
for more than 1 million iterations.
The reason is, result_array
stores all data in an array - and sooner or later you'll get a memory limit problem.
In order to avoid this you have to use unbuffered_row
.
This method returns a single result row without prefetching the whole result in memory.
Take a look at their documentation here. (section unbuffered_row)
The next thing i would change are your if blocks - i would use the if/else
syntax here. (it isn't that big of a difference but considering your amount of rows - it might helps)
Also, i outsourced the block where you calculate your rating twice with the same logic behind.
Basically the following should work:
function rows_update()
{
$currency_numbers_after_dot = $this->currencies_model->get_currency('ONE', 'My currencty')['numbers_after_dot'];
$game_currency_percentage_max = $this->settings_model->get_settings_details('game_rating_percentage_max')['value'];
$game_currency_speed_in_hour = $this->settings_model->get_settings_details('game_currency_speed_in_hour')['value'];
$this->db->from('members');
$query = $this->db->get();
$arrUpdateBatchData = [];
while ($row = $query->unbuffered_row('array'))
{
$game_total_balance = round($row['game_vault_balance'] + $row['game_available_balance'], $currency_numbers_after_dot);
if ($game_total_balance > 0) {
// Game Rating Calculate
// Rating Part1
// Rating Part1_1
$rating_part1_1 = $this->getRatingPart($row['game_vault_balance']);
$rating_part1_2 = $this->getRatingPart($game_total_balance);
// Rating part1_3
$rating_part1_3 = 0;
// Rating part1_4
$rating_part1_4 = 0;
// Rating part2
$PER_part2 = '0';
// Rating part3
$PER_part3 = '0';
// Calculate all rating
$rating = round($rating_part1_1 + $rating_part1_2 + $rating_part1_3 + $rating_part1_4 + $rating_part2 + $rating_part3, 2);
if ($rating <= 1) {
$rating_member = $rating;
}
elseif ($rating > 1) {
$rating_member = floor($rating);
}
// Game balance calculate
$amount_from_game_vault_in_hour = $game_currency_speed_in_hour / '100' * $row['game_vault_balance'];
$new_balance_in_hour = ($game_currency_percentage_max / '100') * $row['rating'] * $amount_from_game_vault_in_hour;
$game_balance_in_hour_amount = $amount_from_game_vault_in_hour + $new_balance_in_hour;
$arrUpdateData = [
'UserID' => $row['UserID'],
'game_vault_balance' => ($row['game_vault_balance'] - $amount_from_game_vault_in_hour),
'game_available_balance' => ($row['game_available_balance'] - $game_balance_in_hour_amount),
'rating' => $rating_member,
'game_rating_and_balance_update_last_time' => date('Y-m-d H:i:s')
];
$arrUpdateBatchData[] = $arrUpdateData;
}
if (count($arrUpdateBatchData) > 500)
{
$this->db->update_batch('members', $arrUpdateBatchData, 'UserID');
$arrUpdateBatchData = [];
}
}
//update last items
if (count($arrUpdateBatchData) > 0)
{
$this->db->update_batch('members', $arrUpdateBatchData, 'UserID');
$arrUpdateBatchData = [];
}
return;
}
function getRatingPart($val)
{
if ($val == 0) {
$rating_part = 0;
}
elseif ($val > 0 AND $val < 20)
{
$rating_part = '0.1';
}
elseif ($val > 20 AND $val < 2000)
{
$max_game_vault_balance = 2000;
$percent = floor($val * 100 / $max_game_vault_balance);
$additional_rating = 0.05 * $percent / 100;
$rating_part = round(0.1 + $additional_rating, 2);
}
else {
$rating_part = 0.15;
}
return $rating_part;
}
Updating 40 million mysql cells at once
The syntax for it would be something like this:
INSERT INTO much_larger_table (cols...)
SELECT cols... FROM a_table
WHERE ...conditions...;
(I am using some placeholders because you haven't described your tables.)
There's no limit to the number of rows you can copy using syntax like this, but there's a practical limit to how many you want to do in one batch.
It will take time of course. We can't predict how long it will take, because it depends on a lot of factors specific to your server and your tables. It's possible that it will take more than the hour in between your scheduled tasks.
The risk is that an INSERT...SELECT statement like this locks the rows as they are read from the origin table. This means no session can modify those rows, and maybe cannot even insert or update other rows in that table, depending on gap locking.
I tell the developers at my company to limit batches to 1000 rows per transaction. This allows each transaction to finish quickly, reduces the number of rows locked and the duration of the lock, and allows MySQL garbage collection to continue.
Related Topics
Splitting SQL Column into Multiple Columns Based on Value
How to Combine Two Completely Different SQL Queries into One Result
Query City Names Starting and Ending With Vowels
How to Make SQL Query Result Show With 2 Decimals
How to Select All the Columns of a Table Except One Column
How to Concatenate Many Rows With Same Id in SQL
Sql: Update Column With Increment Numbers Based on 2 Columns
How to Use SQL Like Condition With Multiple Values in Postgresql
Select Every Employee That Has a Higher Salary Than the Average of His Department
Better Techniques for Trimming Leading Zeros in SQL Server
Check If a Column Contains Text Using SQL
Sql Server Function to Return Minimum Date (January 1, 1753)
Inserting Date Value into Date Field Using Laravel
How to Select True/False Based on Column Value
Mysql in Xampp Starts and Stops in Five Seconds
Job for Mysqld.Service Failed See "Systemctl Status Mysqld.Service"