As always... it depends.
What follows is my opinion. It is only opinion, which means you are free to ignore most or all of it.
As for primary keys, Int versus TinyInt.
I would never use anything less than an Int for a primary key. There are times when I would consider BigInt or UniqueIdentifier, but my go-to is usually int. If you have a table with less than 255 rows, and you are worried about optimizing the data storage, then I would easily argue that you are wasting your time. Most likely, SQL server will cache this data in RAM and access it from there. It's a tiny table and easily stored.
I do use TinyInt, SmallInt, and lots of other data types, but only for actual data. For example, "speed limit" in my database is stored in miles per hour and is a tiny int.
Regarding char versus varchar.
I kinda detest the char type because it is "space padded". What I mean is, if you have a char(8) column, with the value in one row of "Yes", SQL will actually store Y-e-s-(space)-(space)-(space)-(space)-(space). When you retrieve this data into your front end, you will have the spaces on the end, which is easy enough to accommodate with a trim, but there will likely be a bunch of places in code where you need to do this. For example, I have a license plate column in one of my tables, it is defined as "[License] [varchar](10) NULL". Most of the data has 7 characters. Do I care? Not even a little bit.
It's true that you want as many rows to fit on a data page as possible because there are speed benefits to doing so. SQL Server stores data on disk as 8k pages. Each page is always read in its entirety and written in its entirety. Therefore, the more rows you can fit on a data page, the better.
For practical purposes, I don't really try to optimize small things. I only worry about tables with more than about 100,000 rows. And in those circumstances, the optimizations usually revolve around indexes, not data types. In my 25 years of owning my own business, with a niche app, I've gone through several iterations of making fields bigger. Every time has been a pain. Best to avoid this if possible. For example, in version 1, I had "student's homeroom assignment" as a varchar(4). I needed to expand this to varchar(10) several years later. This required me to distribute a new application because the text box had a maxlength hardcoded in it.
I strongly suggest you limit the number of varchar(max) data types. There are times when you need them, and therefore should use them when appropriate. Licese Plate would not be an appropriate use for varchar(max). I do have several columns in several tables with the varchar(max) data type, but they are generally used for comment columns. I also use varchar(max) for driving directions from one stop to another. Only use this data type if you are expecting a very large amount of text. Varchar(max) columns are generally a lot slower than varchar(size) columns. There are technical reasons for this based on the way SQL Server stores the data on disk. Suffice to say, only use them when you need to.
PS. There are some county names greater than 20 characters. In the US, I see some county names up to 24 characters. There's a "SAINT JOHN THE BAPTIST" county in Louisiana and several in Alaska. In Canada, I see longer ones.
-George
Microsoft SQL Server MVP
My Blogs
SQLCop
twitter
"The great things about standards is that there are so many to choose from." - Fortune Cookie Wisdom