Postgres Can't Add Foreign Key Constraint
about how long should it take


It depends on the amount of data, your indexes, and the speed of your IO sub-system (the latter particularly if supporting indexes aren't in place).

As you already have 220 million rows in the child table, it must check each of them against the parent table to make sure they are all valid values. Without a useful index on events.visitor this will mean scanning the whole table.

Note that creating a foreign key does not automatically create a supporting index, because depending on your access patterns such an index may not be needed so would be a waste of space.


  What's the fastest way to do this, 


You can tell the DB not to validate the foreign key constraint for existing rows by adding NOT VALID (see the documentation at https://www.postgresql.org/docs/current/sql-altertable.html for the details and caveats associated with this). That is the fastest way but can lead to you having rows that are invalid that you do not know about until they cause a problem.
(NOT VALID is postgres specific syntax, other DBs that offer the option may name it differently, for instance with MS SQL Server the equivalent is WITH NOCHECK)

The second fastest method is to make sure there is an index on that column before defining the foreign key, though creating that index will itself take a notable amount of time on a table of that many rows.


  I tried again and it ended up completing in around half an hour. Not sure what was going on before.


It may be that at the point of the later attempt much of the table was in memory after being read during the earlier aborted create, so scanning to validate existing rows was faster second time around due to fewer disk reads being needed.