Question

We have an external PHP script that pulls data from various tables in the database to create an update to a couple other tables in the same database. For the purposes of this question I won't go into what that script pulls or how it generates the data, but what I'm interested in is how it updates its tables in the database.

Currently the script does not do any sort of diff, rather it creates a SQL script that creates a temporary table and inserts the data it generated into that temporary table. It then TRUNCATEs the production table and INSERT/SELECT everything from the temporary table. I should note that the data generated by this script could be different every time it runs, based off what's removed, added, or changed in other tables.

Here's a sanitized version of what it's doing:

CREATE TEMPORARY TABLE tbl0_temp (col1, col2, col3, PRIMARY KEY  (col1,col), UNIQUE KEY tuple (user_id,nas_id));

INSERT INTO tbl0_temp VALUES (valA1, valB1, valC1),(valA2, valB2, valC2),(valA3, valB3, valC3),...you get the idea.

TRUNCATE TABLE tbl0_prod;

INSERT INTO tbl0_prod SELECT * FROM tabl1_temp;

That method worked fine where there were just a couple thousand lines in the production table (tbl0_prod) years ago, but now we have closer to a couple million. Given that, the method isn't ridiculously slow, but on some replicas the INSERT/SELECT can take up to 30 seconds. That's 30 seconds the applications on the remote machines are not getting the data they need, and folks do notice.

I'm hoping there is a better, quicker, and less impactful way to update that table. I was wondering if creating/updating a "real" table and simply doing a few renames would work. Here's an example of what I'm thinking:

CREATE TABLE IF NOT EXISTS tbl0_temp LIKE tbl0;

TRUNCATE TABLE tbl0_temp;

INSERT INTO tbl0_temp VALUES (valA1, valB1, valC1),(valA2, valB2, valC2),(valA3, valB3, valC3),...

RENAME TABLE tbl0 TO tbl0_old, tbl0_temp to tbl0;

RENAME TABLE tbl0_old TO tbl0_temp;

The thought behind keeping the tbl0_tmp table is if something went wrong it'd be pretty easy to rename stuff back, but alternately I could just drop tblo_old and not even have to worry about the truncate at the beginning. In my head this seems like it's a good idea, but this is where I've hit a knowledge gap with what the repercussions may be on the backend. Does anyone happen to have any insight (with the limited information I've provided) as to if this would or would not work, or be a bad idea?

The versions on the primary and most replicas are 5.0.46. All the tables in question are MyISAM.

Was it helpful?

Solution

FYI...for what I needed to do, the method I described works perfectly.

CREATE TABLE IF NOT EXISTS tbl0_temp LIKE tbl0;

TRUNCATE TABLE tbl0_temp;

INSERT INTO tbl0_temp VALUES (valA1, valB1, valC1),(valA2, valB2, valC2),(valA3, valB3, valC3),...

RENAME TABLE tbl0 TO tbl0_old, tbl0_temp to tbl0;

RENAME TABLE tbl0_old TO tbl0_temp;

OTHER TIPS

The method I use is neither of those:

INSERT IGNORE INTO tbl0 
VALUES 
(valA1, valB1, valC1),
(valA2, valB2, valC2),
(valA3, valB3, valC3),...

Or

REPLACE INTO tbl0 
VALUES 
(valA1, valB1, valC1),
(valA2, valB2, valC2),
(valA3, valB3, valC3),...

Or if for some reason I wanted to have some very complex rules I'd use a trigger.

If you want to preserve the oriinal table, then create a copy of it first, insert into the copy, then rename the live table as a backup and the new table as the live (same process as zero-downtime schema changes).

(have you considered changing to Innodb - it has much better concurrency support, and in some contexts will run faster than MyISAM).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top