Both ways can be valid depending on the scenario.
Method 2 is the more standard, common way. It is a 1-N relationship only N is either 0 or 1. FK columns are by default indexed in most databases and go on the table on the N side (just like you describe with your unique index only an additional FK constraint fails if you insert an FK-column-value which does not match any PKs in A).
Method 1 follows the same structure as an N-1 relationship (FK column is on the N side). It can be done for example in hibernate using a ManyToOne relationship where optional=true. It is an N-to-0/1 relationship where N happens to be always 1.
Method 1 can make complete sense. Say A is "Client" and B is "SalesContact". Client will only have 0 or 1 SalesContact. Perhaps each SalesContact is only assigned to 1 Client. But we want to support SalesContact being assigned to multiple Clients in the future.
Method 2 can make complete sense. Say you have "Client" and "Address". An Client can have 0 or 1 Address. But in the future, we want to support clients having multiple addresses.
But if you know you will always have 1-to-0/1 and will never want 1-N or N-1 in the future, you can choose either way. Method 2 is probably a better choice.
Most ORMs do not have a 1-to-0/1 construct specifically, just 1-N, N-1 and maybe 1-1. In hibernate, the 1 side of 1-N/N-1 can be 0 for optional=true.
Further note: I am currently considering Method 1 for efficiency reasons. But I notice at least in mysql that SELECT * WHERE key = NULL
(not IS NULL
, outright null-lookup-in-index similar to key = :inserted_value
with inserted_value as null), EXPLAIN is indicating an index lookup anyways! You might think that if the key NULL is being looked up in the index, the db would just skip the lookup and return nothing (maybe it still does that, I'm not sure). Not only that but when I log generated SQL from hibernate, using ManyToOne + optional=true + Eager it always does a left join - when I look up either 1 or multiple A's. When I switch to optional=false (N-1 not N-to-0/1), it changes the left join to an inner join. So in my case, OneToMany and ManyToOne are both table joins. It is possible that the db engine is still faster on ManyToOne but only if it starts with the A table and is smart enough to skip the null lookup on B. Note that whether the db engine starts with A or B is up to the db engine query optimization logic but for certain queries it will always choose A.