So what can you take home with you? First, you can take home that some folks can talk about just about anything for a long time. Second, you can take home that, while this may not be busting a myth, it is putting an adage in perspective. What I mean is that while the adage that integer joins are faster than variable character joins is true, that does not necessarily mean you should always opt for creating a lookup table, regardless of what academic rules might dictate.
I would suggest that if the lookup table has only one value in it, that of a semantically pertinent and (de facto) unique value, such as the name of a country, you should seriously consider just duplicating that character data for the sake of simplicity, usability (from a developer and report writer perspective), and performance (remember the last test—if you don’t join, the query is notably faster).
You can still constrain entry to a list. In fact, if you do go ahead and create a separate table to store the list values, you can more easily keep those values in sync even if they change by taking advantage of the cascading update option available in SQL Server. But you don’t have to refer back to the list every time you want to display meaningful data for other tables that use data from your list.
Also keep in mind that if you do need to do a lookup in such cases, it is not all that bad, really, especially if you’re not dealing with many, many rows. If you find that you think the benefits of a semantically meaningful key are worth sacrificing a few milliseconds here and there, go for it.
However, if you do not have such a key for an entity, do not want to rely on users to create one (if that’s an option), or will be dealing with multiple millions of records, you should probably stick with the integer key approach. If you will be replicating a lot, though, you may want to consider using the UNIQUEIDENTIFIER column type for your artificial keys, as that can simplify situations, though it too has drawbacks that we won’t cover here.