unique_integer([monotonic]) needs to be synchronized across the schedulers, so these are slower than non-monotonic unique_integer or make_ref.
Both non-monotonic unique_integer and make_ref use a similar way to construct themselves, using a pool exclusive for each scheduler. However, the unique_integer pool is always started at the same value whereas the reference pool uses the current time as a seed.
Moreover, the guarantees for unique_integer are only related to the current node. You can run erl -eval 'io:format("~p", [erlang:unique_integer()]),init:stop().' several times in a row and you'll see repeated values. Thus, if you have a cluster, the integers may not be unique.
On the other hand, as references include the node that created them, they are unique across the connected nodes in a cluster.
When using persisted data, you need to account for possible ERTS restart, and thus you cannot strongly guarantee uniqueness in time. Although using references may be enough (as I've shown that unique_integer is not strong enough when accounting for node restart), maybe you should use a different strategy such as having the persistence layer create the ids for you when you store the data (AUTOINC in MySQL).
But you can mix and match these as you wish. You can have each node pull an unique integer (let's call it node-id) from the persistence layer on boot and combine it with the unique_integer in a larger integer. Or you can have each node generate its own node-id with a combination of start time, strong randomness and a hash of its own name... It all depends on the requirements of your use case.