How to query for address "predictions" while applying constraints
3 tables is what I call "over-normalizing" -- it leads to performance problems.

"Normalizing" is used for two purposes, neither of which really apply to your use case.


Isolate something, say "city" so that it can be easily changed.  In real life, that rarely happens for cities.  ("Bombay" -> "Mumbai" (India), "Hot Springs" -> "Truth or Consequences" (New Mexico))
Save space.  Even if you have all 3 million cities on earth, spelling them out the country each time is not much burden of space.  (For countries, I recommend the standard 2-letter country-codes and use CHARACTER SET ascii.  Optionally, have a table mapping them to spelled out names.)


Zip codes:  In the US, there are about 42K zip-codes.  To normalize you could use a 2-byte SMALLINT UNSIGNED.  But the zipcode, itself, can be stored in a 3-byte MEDIUMINT(5) UNSIGNED ZEROFILL.  Zipcodes do change.  But that usually involves forcing half the users of one zipcode to adopt a 'new' zipcode.  You would have to go through all users of that zipcode (which could be INDEXed) to figure out which ones to change.

Similarly for the split-up of Yugoslavia and Czechoslovakia.  On the other hand, changing "The Republic of Upper Volta" to "Burkina Faso" is easy if you have 'normalized' it.

Plan A (millions of locations):  Simply spell out the location of each item.

Plan B (billions of locations):  Split in two:  Street address and zip+city+country

Think about it another way:  What will you do with the address?


Only for sending mail?  Then why split up the pieces; simply have some text that can be readily printed as-is.
Also used for statistics?  Then you need, say, the "country" (or "country_code") so you can do SELECT SUM... GROUP BY country_code.  This implies that country_code is a separate column.