You are using procedural processing, where you do something for each record in TEMP_VOICE_USAGE. The "something" is the execution of 2 SQL statements (1x INSERT or UPDATE and 1x DELETE). It is not very surprising that it performs poorly for you. Especially if you consider that the DELETE is a searched-delete and not a positioned-delete. (A positioned delete uses WHERE CURRENT OF <cursor>.)
You may want to use SQL in a set-oriented fashion. You may want to use the MERGE statement. Another option would be to have 1x INSERT for all new records, 1x UPDATE for all existing ones and then a single DELETE (no loops):
Code:
INSERT INTO usage_data
SELECT ... FROM temp_usage_data AS t
WHERE NOT EXISTS ( SELECT 1 FROM usage_data AS u WHERE u.msisdn_no = t.dup_voice_recs
UPDATE usage_data AS u
SET u.mou = ( SELECT u.mou + SUM(DOUBLE(t.mou)) FROM temp_voice_usage AS t WHERE u.msisdn = t.dup_voice_recs )
WHERE EXISTS ( SELECT 1 FROM temp_voice_usage AS t2 WHERE u.msisdn = t2.dup_voice_recs )
DELETE FROM temp_voice_usage
(modulo typing errors)