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
OrderID
column is defined asSERIAL
, and so it will be automatically assigned sequential values starting from 1. OrderID
is also defined as thePRIMARY KEY
of 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
BIGINT
column 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
INT
instead ofBIGINT
to 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:
SERIAL
is alwaysBIGINT
, whileAUTO_INCREMENT
can be applied to any integer type (e.g.,TINYINT
,INT
,BIGINT
, etc). - Syntax:
SERIAL
is a shorthand for defining an auto-incrementingBIGINT
column with additional constraints, whileAUTO_INCREMENT
must be explicitly paired with a column type. - Flexibility:
AUTO_INCREMENT
gives 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,
SERIAL
is 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_INCREMENT
mechanism. PostgreSQL also offersBIGSERIAL
, which behaves like MySQL’sSERIAL
, mapping to aBIGINT
with a sequence, as well asSMALLSERIAL
, which maps to aSMALLINT
with a sequence. The default starting value and increment can be customized more easily in PostgreSQL using sequences. - Oracle: Oracle doesn’t have a
SERIAL
type, but auto-increment behavior can be mimicked using sequences and triggers. From Oracle 12c onward, there is anIDENTITY
column feature that functions similarly toAUTO_INCREMENT
in MySQL. - SQL Server: SQL Server also lacks a
SERIAL
type but offersIDENTITY
, which provides similar functionality toAUTO_INCREMENT
in 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
. UsingSERIAL
will always default toBIGINT
, even ifINT
would 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.