If you work with MySQL databases, you may have encountered the SERIAL type in a table’s definition. And if you’ve come over from PostgreSQL, you might have a false expectation about how MySQL’s SERIAL works – unless you already know 😉
Below is a quick overview of MySQL’s SERIAL type, including an explanation of how it differs from PostgreSQL’s SERIAL type and similar functionality from other DBMSs.
What is the SERIAL Type in MySQL?
In MySQL, SERIAL is not exactly a true data type but rather a convenient alias for a combination of BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE. It’s used to generate sequential, automatically incrementing numbers for a column, typically intended for use as a primary key.
When you define a column as SERIAL, MySQL treats it as an unsigned BIGINT (which is an 8-byte integer with a range of 0 to 18,446,744,073,709,551,615) with the AUTO_INCREMENT attribute, meaning the value will automatically increase with each new row inserted. It also ensures the column cannot contain NULL values and that it is unique.
Example of SERIAL in MySQL
Here’s an example of creating a table that has a SERIAL column defined:
CREATE TABLE Orders (
OrderID SERIAL,
CustomerID INT,
OrderDate DATE,
PRIMARY KEY (OrderID)
);
In this example:
- The
OrderIDcolumn is defined asSERIAL, and so it will be automatically assigned sequential values starting from 1. OrderIDis also defined as thePRIMARY KEYof the table, so it uniquely identifies each row.
Once we’ve run the above code, when we use SHOW CREATE TABLE to view the table’s definition, we can see the full definition of the SERIAL column:
SHOW CREATE TABLE Orders;
Output:
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Orders | CREATE TABLE `orders` (
`OrderID` bigint unsigned NOT NULL AUTO_INCREMENT,
`CustomerID` int DEFAULT NULL,
`OrderDate` date DEFAULT NULL,
PRIMARY KEY (`OrderID`),
UNIQUE KEY `OrderID` (`OrderID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
We can see that the definition for the OrderId column is bigint unsigned NOT NULL AUTO_INCREMENT. In fact, the word SERIAL is nowhere to be found.
When to Use SERIAL vs. AUTO_INCREMENT in MySQL?
While SERIAL is a shortcut, using AUTO_INCREMENT is more flexible. You can apply AUTO_INCREMENT to any integer column, and it can be paired with any integer data type (like INT, BIGINT, MEDIUMINT, etc), not just BIGINT like in SERIAL.
Use cases for SERIAL:
- When you need a simple auto-incrementing
BIGINTcolumn and don’t want to manually specify all the attributes. - When the size of your table might grow beyond the limits of
INT, so you prefer the largerBIGINT.
Use cases for AUTO_INCREMENT:
- When you need more control over the column type (e.g., using
INTinstead ofBIGINTto save storage space). - When you need to set the starting value or step for auto-increment (e.g., you can set the first value to 1000 or increment by 5).
Differences Between SERIAL and AUTO_INCREMENT
- Data Type:
SERIALis alwaysBIGINT, whileAUTO_INCREMENTcan be applied to any integer type (e.g.,TINYINT,INT,BIGINT, etc). - Syntax:
SERIALis a shorthand for defining an auto-incrementingBIGINTcolumn with additional constraints, whileAUTO_INCREMENTmust be explicitly paired with a column type. - Flexibility:
AUTO_INCREMENTgives you more flexibility because it can be used with different integer types and allows for customization of starting points and increments.
How Does SERIAL in MySQL Compare to Other DBMSs?
Other DBMSs have similar functionality, in that they provide us with an easy way to get an incrementing value. That said, there are differences from DBMS to DBMS. Here’s a quick comparison with a few of the major DBMSs:
- PostgreSQL: In PostgreSQL,
SERIALis a true data type, which can be used withSMALLINT,INT, orBIGINT. It implicitly creates a sequence object behind the scenes to handle auto-incrementing behavior. In contrast, MySQL does not create a separate sequence object forSERIAL; it directly uses theAUTO_INCREMENTmechanism. PostgreSQL also offersBIGSERIAL, which behaves like MySQL’sSERIAL, mapping to aBIGINTwith a sequence, as well asSMALLSERIAL, which maps to aSMALLINTwith a sequence. The default starting value and increment can be customized more easily in PostgreSQL using sequences. - Oracle: Oracle doesn’t have a
SERIALtype, but auto-increment behavior can be mimicked using sequences and triggers. From Oracle 12c onward, there is anIDENTITYcolumn feature that functions similarly toAUTO_INCREMENTin MySQL. - SQL Server: SQL Server also lacks a
SERIALtype but offersIDENTITY, which provides similar functionality toAUTO_INCREMENTin MySQL.
When Not to Use SERIAL
While SERIAL in MySQL provides us with a concise way to define an auto-incrementing column, there are times you might not want to use it. For example:
- When you need finer control over the starting value or increment behavior, in which case you might prefer
AUTO_INCREMENT. - When storage space is a concern, and you don’t need the full range of
BIGINT. UsingSERIALwill always default toBIGINT, even ifINTwould suffice for your use case.
Applying SERIAL to Other Integer Types
When I said that SERIAL is limited to just BIGINT, maybe that was only half true. MySQL also offers the SERIAL DEFAULT VALUE syntax which allows us to apply SERIAL attributes to other integer types.
SERIAL DEFAULT VALUE is an alias for NOT NULL AUTO_INCREMENT UNIQUE.
So we could do the following for example:
CREATE TABLE Orders (
OrderID INT SERIAL DEFAULT VALUE,
CustomerID INT,
OrderDate DATE,
PRIMARY KEY (OrderID)
);
Output:
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Orders | CREATE TABLE `orders` (
`OrderID` int NOT NULL AUTO_INCREMENT,
`CustomerID` int DEFAULT NULL,
`OrderDate` date DEFAULT NULL,
PRIMARY KEY (`OrderID`),
UNIQUE KEY `OrderID` (`OrderID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
We can see that the definition for the OrderID column is int NOT NULL AUTO_INCREMENT.
So while it’s not quite as concise as using SERIAL, it does allow us to leverage its functionality for other integer types.