When is space be allocated in databases?
(This Answer addresses MySQL with ENGINE=InnoDB.)

Your specific question:  Use TINYINT UNSIGNED instead of INT to save 3 bytes per row (on disk and in cache).  Do it.

Basic guidelines (and TMI):

All numeric types (at least for NOT NULL) are fixed length, regardless of the value stored in them:


TINYINT - 1 byte
INT - 4 bytes
DOUBLE - 8 bytes
DECIMAL(m,n) about m/2 bytes.  (The exact number of bytes is complicated.)


SIGNED vs. UNSIGNED has not impact on space.  Instead, it impacts the range for *INT types.  Eg, TINYINT SIGNED is -128..127; TINYINT SIGNED is 0..255.

NULL vs NOT NULL -- the space consumed is complex due to MVCC, potential for ROLLBACK, the storage in BTree structure, etc.  It is not worth thinking of NULL as a way to save space.  Decide between NULL vs NOT NULL based on business logic, not space.  OK, you could let 0 or '' be used instead of NULL.  But, again, the space difference is so minuscule and complex to compute that it is not worth it. 
 I think that NULL vs NOT NULL either matters or does not, depending on the ROW_FORMAT.

Make the decision between a 4-byte INT and a 1-byte TINYINT (or other sizes) when you originally create the table; it is costly to change it later.  Be conservative; maybe there are only 10K thingies today, but if the landscape changes, might you exceed the 64K limit of SMALLINT UNSIGNED tomorrow?

Most database data can be UNSIGNED.

String types (VARCHAR, TEXT, BLOB, etc) are typically variable length, with a 1- or 2-byte length prepended to the space.

CHAR(10) CHARACTER SET utf8mb4 NOT NULL takes 10 to 40 bytes, plus at least 1 byte overhead.  VARCHAR(10) CHARACTER SET utf8mb4 (NULL or NOT NULL) takes 0 to 40 bytes, plus at least 1 byte overhead.  (There may be ROW_FORMAT dependencies here, too.)  TEXT, VARBINARY, and BLOB act similar to VARCHAR.

Priority #1:  Business logic
Priority #2:  Space