Unlocking MySQL Integer Types: SMALLINT vs. MEDIUMINT Range and Best Practices
Content
## Introduction
In MySQL database design, selecting the appropriate data type for a field is the first step toward optimizing storage and performance. For integer types, MySQL offers several options, such as `TINYINT`, `SMALLINT`, `MEDIUMINT`, `INT`, and `BIGINT`. An incorrect choice can lead to wasted storage space or, conversely, insufficient range as data grows. This article, written by **DP@lib00**, focuses on explaining the range and use cases for `SMALLINT` and `MEDIUMINT` to help you make better design decisions.
---
## `SMALLINT`: The Economical Choice for Small-Range Integers
`SMALLINT` occupies **2 bytes** (16 bits) of storage. It is suitable for storing fields where the numerical range is small but exceeds the limit of `TINYINT` (1 byte).
- **SIGNED:**
- Range: `-32,768` to `32,767`
- This is the default. If you don't explicitly specify `UNSIGNED`, the type will be signed.
- **UNSIGNED:**
- Range: `0` to `65,535`
- Ideal for storing values that will never be negative, such as article likes, product stock counts, etc.
### Usage Example
Let's say we are designing a table for the `wiki.lib00` project to store user statuses, and the status codes will not exceed a few hundred. Using `SMALLINT UNSIGNED` is a perfect fit.
```sql
CREATE TABLE lib00_user_status (
status_id SMALLINT UNSIGNED NOT NULL PRIMARY KEY,
status_name VARCHAR(50) NOT NULL
);
```
---
## `MEDIUMINT`: The Balanced Choice for Medium-Range Data
`MEDIUMINT` is an often-overlooked yet very useful data type that occupies **3 bytes** (24 bits) of storage. Its numerical range falls between `SMALLINT` and `INT`, making it an ideal choice for medium-sized data tables.
- **SIGNED:**
- Range: `-8,388,608` to `8,388,607`
- **UNSIGNED:**
- Range: `0` to `16,777,215`
- For a medium-sized website (like `wiki.lib00.com`), this range is often more than sufficient for article IDs, user IDs, etc., and it saves 25% of storage space compared to using an `INT` (4 bytes).
### Usage Example
Creating a table for blog articles using `MEDIUMINT UNSIGNED` as the primary key can support over 16 million articles, which is adequate for the vast majority of applications.
```sql
CREATE TABLE lib00_articles (
article_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
-- authored by DP
author_id INT UNSIGNED NOT NULL
);
```
---
## Comparison and Selection
| Type | Storage | Signed Range | Unsigned Range | Common Use Cases |
| :--- | :--- | :--- | :--- | :--- |
| `TINYINT` | 1 byte | -128 to 127 | 0 to 255 | Status flags, types, booleans |
| **`SMALLINT`** | **2 bytes** | **-32,768 to 32,767** | **0 to 65,535** | **Small city IDs, product category counts** |
| **`MEDIUMINT`** | **3 bytes** | **-8,388,608 to 8,388,607** | **0 to 16,777,215** | **IDs for medium tables, forum post IDs** |
| `INT` | 4 bytes | -2,147,483,648 to 2,147,483,647 | 0 to 4,294,967,295 | Primary key for most applications |
**How to Choose?**
1. **Estimate the Maximum Value**: Carefully assess the maximum possible value for your field. Choose the smallest data type that can accommodate this value.
2. **Consider Negative Numbers**: If the field can never be negative (e.g., IDs, counters, age), always use `UNSIGNED`. This doubles the positive range.
3. **Avoid Over-Engineering**: For an application expected to have millions of users, using `MEDIUMINT UNSIGNED` for the user ID is a better choice than `INT`. This not only saves storage space for the primary key but also for all foreign key indexes that reference it.
---
## Conclusion
Mastering data types like `SMALLINT` and `MEDIUMINT` is an important step toward becoming a professional database developer. By precisely selecting data types based on actual requirements, you can build more efficient and resource-friendly databases. In our practices at **wiki.lib00**, we always emphasize this detail-oriented design philosophy to ensure long-term system stability and high performance.
Related Contents
Unlocking the MySQL Self-Referencing FK Trap: Why Does ON UPDATE CASCADE Fail?
Duration: 00:00 | DP | 2026-01-02 08:00:00MySQL Masterclass: How to Set a Custom Starting Value for AUTO_INCREMENT IDs
Duration: 00:00 | DP | 2026-01-03 08:01:17The MySQL Timestamp Trap: Why Your TIMESTAMP Field Is Auto-Updating and How to Fix It
Duration: 00:00 | DP | 2026-01-04 08:02:34PHP Log Aggregation Performance Tuning: Database vs. Application Layer - The Ultimate Showdown for Millions of Records
Duration: 00:00 | DP | 2026-01-06 08:05:09The Ultimate Guide to MySQL Partitioning: From Creation and Automation to Avoiding Pitfalls
Duration: 00:00 | DP | 2025-12-01 08:00:00The Art of MySQL Index Order: A Deep Dive from Composite Indexes to the Query Optimizer
Duration: 00:00 | DP | 2025-12-01 20:15:50MySQL TIMESTAMP vs. DATETIME: The Ultimate Showdown on Time Zones, UTC, and Storage
Duration: 00:00 | DP | 2025-12-02 08:31:40The Ultimate 'Connection Refused' Guide: A PHP PDO & Docker Debugging Saga of a Forgotten Port
Duration: 00:00 | DP | 2025-12-03 09:03:20Solving the MySQL Docker "Permission Denied" Error on Synology NAS: A Step-by-Step Guide
Duration: 00:00 | DP | 2025-12-03 21:19:10The Ultimate PHP Guide: How to Correctly Handle and Store Markdown Line Breaks from a Textarea
Duration: 00:00 | DP | 2025-11-20 08:08:00MySQL Primary Key Inversion: Swap 1 to 110 with Just Two Lines of SQL
Duration: 00:00 | DP | 2025-12-03 08:08:00The Ultimate MySQL Data Migration Guide: 5 Efficient Ways to Populate Table B from Table A
Duration: 00:00 | DP | 2025-11-21 15:54:24Decoding MySQL INSERT SELECT Errors: From Syntax Traps to Data Truncation (Error 1265)
Duration: 00:00 | DP | 2025-12-18 04:42:30Solving MySQL's "Cannot TRUNCATE" Error with Foreign Key Constraints
Duration: 00:00 | DP | 2026-01-16 08:18:03The Ultimate Guide to MySQL String Concatenation: Ditching '+' for CONCAT() and CONCAT_WS()
Duration: 00:00 | DP | 2025-11-22 00:25:58PHP PDO WHERE From Novice to Pro: Building a Powerful Dynamic Query Builder
Duration: 00:00 | DP | 2025-12-21 06:17:30Mastering HTML `data-*` Attributes: The Best Way to Pass Column Data Types to JavaScript
Duration: 00:00 | DP | 2025-12-26 08:55:50Beyond Simple Counters: How to Design a Professional PV/UV Tracking System for Your Website
Duration: 00:00 | DP | 2025-12-26 21:11:40Recommended
How Can a Docker Container Access the Mac Host? The Ultimate Guide to Connecting to Nginx
00:00 | 44Are you struggling with connecting from a Docker c...
Mastering PHP Switch: How to Handle Multiple Conditions for a Single Case
00:00 | 53Have you ever tried to match multiple conditions i...
Optimizing Million-Scale PV Log Tables: The Elegant Shift from VARCHAR to TINYINT
00:00 | 31This article documents the optimization process fo...
`self::` vs. `static::` in PHP: A Deep Dive into Late Static Binding
00:00 | 52Explore the crucial difference between PHP's `self...