Indexes: integer vs string performance if the number of nodes is the same
Short answer: integer is faster than varchar or text in every aspect. Won't matter much for small tables and / or short keys. The difference grows with the length of the keys and the number of rows.


  string ... 20 characters long, which in memory is roughly 5x that of
  the integer (if an integer is 4 bytes, and the strings are pure ASCII
  at 1 byte per character, then this holds)


To be precise, character types (text or varchar) occupy exactly 21 bytes for 20 ASCII characters on disk and 23 bytes in RAM. Detailed assessment:


What is the overhead for varchar(n)?


Also important: COLLATION rules can make sorting character data more expensive - unlike numeric data types:


Would index lookup be noticeably faster with char vs varchar when all values are 36 chars


Index size is probably responsible for the lion share of performance difference in most cases. Consider the overhead per index tuple (basically the same as for a table): 4 bytes for the item identifier and 8 bytes for the index tuple header. So the index tuple for integer would amount to 20 bytes (including 4 bytes of alignment padding) and for varchar(20) with 20 ASCII characters it would be 36 bytes (also incl. padding). Details:


Configuring PostgreSQL for read performance


All the theory aside: it's best to just test:


Measure the size of a PostgreSQL table row


Postgres 9.5 introduced an optimization for sorting long strings of character data (key word "abbreviated keys"). But a bug in some C library functions on Linux forced the project to disable the feature for non-C collations in Postgres 9.5.2. Details in the release notes.

However, if you actually use Postgres enum types, most of these considerations are irrelevant, since those are implemented with integer values internally anyway. The manual:


  An enum value occupies four bytes on disk.


Aside: varchar(255) used to make sense for early versions of SQL Server, which could use a more efficient data type internally up to the limit of 255 characters. But the odd length restriction of 255 characters has no special meaning in Postgres at all.