I my opinion, it's better to check one table for each packet than checking 40000 address list items, but ymmv.
The cost of "searching" an address list is not a linear function of how big the address list is.
The router doesn't go through the list one by one asking "Is this it? Nope. Is this it? Nope. Is this it? ...."
Basically, an IP address maps to a certain hash, meaning that it has a specific place in the list where it will be found if it does exist in the list. All the router needs to do is hash the IP address and go look at that spot - if that spot has a "yes" stored there, then the address is in the list. If there's a "no" stored there, then it's not in the list. The router doesn't need to check all 40000 entries, just the one where the address WOULD be if it WERE in the list. This doesn't mean that it only takes one check though because the hash may map multiple addresses to the same place, in which case the hash function must be applied a second time....
It is not completely certain which Linux method is used below the MikroTik address list feature,
but I think it is the ipset hash:net method.
From reading a few of the ipsets man pages / presentations on the web, it appears that hash:net lookup complexity is roughly linear with the number of unique prefix lengths that exist in your hash. So if you used only /24 entries in your hash, then each lookup only has to hit the hash table 'once,' but if you store both /24 and /16 prefixes, then each lookup must hit the hash table 'twice,' etc. Basically this means that the lookup function takes the IP address being checked and masks it with each possible mask from the hash and looks for matches, starting with the longest-stored prefix length until it finds a match or runs out of prefix lengths to try.
The lookup time also apparently scales linearly with how densely you pack the hash with the probes parameter, so the "once" and "twice" above can become multiple hash(hash(hash(IP-to-test))) when the hash is mostly full, but this seems true of all of the hash types so it doesn't matter in this context.
In general, I'd say that ipset:hash can handle a set that's thousands and thousands of entries huge w/o placing significantly more load on the CPU than just a few entries.
Therefore, I'd imagine that if you do auto-blacklisting in ROS, you can keep lots of load off of the connection state tracking by dropping packets to/from blacklisted addresses in the RAW table's prerouting/output chains. This will prevent the packets from creating lots of connections in the connection state table, especially if these blacklisted addresses are trying to port-scan / ddos your box.
I think another good use of RAW table would be for a case where you want to use state tracking to protect the management plane of the router (input/output chain) but do NOT want to do connection state tracking on the packets flowing through the router - say this is a core router for instance. You could make a rule in the Raw table, prerouting chain:
/ip firewall raw
add chain=prerouting dst-address-type=!local action=notrack
I wonder how the performance of this would compare with completely disabling connection tracking....