This is a large table. In such cases, it usually works better to create a new temporary table, truncate the original, and re-insert the data:
create temporary table temp as
select max(id), lower(domain), status
from mytable
group by lower(domain), status;
truncate table mytable;
insert into mytable(id, domain, status)
select id, domain, status
from temp;
This assumes that you can take the big table offline for a while for the re-insertion. Otherwise, you'll need to delete in batches.
If you want to do it as a delete, I would still start with the same temporary table and add an index on id
. Then do:
delete m
from mytable m left join
temp
on m.id = temp.id
where temp.id is null;
You can add a limit
clause, such as limit 10000
to run this in batches.
NOTE:
The assumption is that you don't care which of the rows to keep. If you just want the biggest id, then use:
create temporary table temp as
select id, lower(domain), status
from mytable m
where not exists (select 1
from mytable m2
where lower(m2.domain) = lower(m.domain) and m2.id > m.id
);
To be honest, though, this will have poor performance. I would check your local settings to see if comparisons are case sensitive or not. If they are not, just add an index on mytable(domain, id)
for the above query. If they are, then put everything in the same case:
update mytable
set domain = lower(domain);
And create the index on mytable(domain, id)
.