Depending on how many rows the inner select returns, you have to do that many comparisons per row in calibration_2009 to see if it has to be deleted.
If the inner select returns 250k rows, then you're doing up to 250k comparisons per row in calibration_2009 just to see if that row should be deleted.
I'd say a faster approach would be to add a column to calibration_2009, if at all possible, called to_be_deleted. Then update that table
UPDATE calibration_2009 SET to_be_deleted = EXISTS (
SELECT 1 FROM `qcvalues`.`batchinfo_2009`
WHERE `batchinfo_2009.rowid = calibration_2009.rowid AND batchinfo_2009.reporttime like "%2010%"
);
That should be pretty quick if both tables are indexed by rowid AND reporttime in batchinfo_2009.
Then just
DELETE FROM calibration_2009 WHERE to_be_deleted = 1;
Then you can delete that new field, or leave it there for future updates.