It's not easy to tell in the absence of test data how big this hash is,
or how many time these loops iterate, but given the sizes of the data files
mentioned in the OP, and the timing information you've supplied above, it
appears that they may be substantial.
####
The next thing I looked at was the section of code where you 'band pass' filter
the matches into a temporary array.
####
Finally (for now), you use this construct:
%{ $sets{ $fasta_id }[ $setscounter ] } = ();
To empty arrays in several places. Whilst there is nothing wrong with this, I think
it is clearer, and may be slightly quicker to use
undef $sets{ $fasta_id }[ $setscounter ] };