mirror of
https://github.com/ramsey/uuid.git
synced 2026-06-14 15:56:48 +03:00
263 lines
8.0 KiB
ReStructuredText
263 lines
8.0 KiB
ReStructuredText
.. _database:
|
|
|
|
===================
|
|
Using In a Database
|
|
===================
|
|
|
|
.. tip::
|
|
|
|
`ramsey/uuid-doctrine`_ allows the use of ramsey/uuid as a `Doctrine field
|
|
type`_. If you use Doctrine, it's a great option for working with UUIDs and
|
|
databases.
|
|
|
|
There are several strategies to consider when working with UUIDs in a database.
|
|
Among these are whether to store the string representation or bytes and whether
|
|
the UUID column should be treated as a primary key. We'll discuss a few of these
|
|
approaches here, but the final decision on how to use UUIDs in a database is up
|
|
to you, since your needs will be different from those of others.
|
|
|
|
.. note::
|
|
|
|
All database code examples in this section assume the use of `MariaDB`_ and
|
|
`PHP Data Objects (PDO)`_. If using a different database engine or
|
|
connection library, your code will differ, but the general concepts should
|
|
remain the same.
|
|
|
|
|
|
.. _database.string:
|
|
|
|
Storing As a String
|
|
###################
|
|
|
|
Perhaps the easiest way to store a UUID to a database is to create a ``char(36)``
|
|
column and store the UUID as a string. When stored as a string, UUIDs require
|
|
no special treatment in SQL statements or when displaying them.
|
|
|
|
The primary drawback is the size. At 36 characters, UUIDs can take up a lot of
|
|
space, and when handling a lot of data, this can add up.
|
|
|
|
.. code-block:: sql
|
|
:caption: Create a table with a column for UUIDs
|
|
:name: database.uuid-column-example
|
|
|
|
CREATE TABLE `notes` (
|
|
`uuid` char(36) NOT NULL,
|
|
`notes` text NOT NULL
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
Using this database table, we can store the string UUID using code similar to
|
|
this (assume some of the variables in this example have been set beforehand):
|
|
|
|
.. code-block:: php
|
|
:caption: Store a string UUID to the uuid column
|
|
:name: database.uuid-column-store-example
|
|
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
$uuid = Uuid::uuid4();
|
|
|
|
$dbh = new PDO($dsn, $username, $password);
|
|
|
|
$sth = $dbh->prepare('
|
|
INSERT INTO notes (
|
|
uuid,
|
|
notes
|
|
) VALUES (
|
|
:uuid,
|
|
:notes
|
|
)
|
|
');
|
|
|
|
$sth->execute([
|
|
':uuid' => $uuid->toString(),
|
|
':notes' => $notes,
|
|
]);
|
|
|
|
|
|
.. _database.bytes:
|
|
|
|
Storing As Bytes
|
|
################
|
|
|
|
In :ref:`the previous example <database.uuid-column-store-example>`, we saw how
|
|
to store the string representation of a UUID to a ``char(36)`` column. As
|
|
discussed, the primary drawback is the size. However, if we store the UUID in
|
|
byte form, we only need a ``char(16)`` column, saving over half the space.
|
|
|
|
The primary drawback with this approach is ease-of-use. Since the UUID bytes are
|
|
stored in the database, querying and selecting data becomes more difficult.
|
|
|
|
.. code-block:: sql
|
|
:caption: Create a table with a column for UUID bytes
|
|
:name: database.uuid-bytes-example
|
|
|
|
CREATE TABLE `notes` (
|
|
`uuid` char(16) NOT NULL,
|
|
`notes` text NOT NULL
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
Using this database table, we can store the UUID bytes using code similar to
|
|
this (again, assume some of the variables in this example have been set
|
|
beforehand):
|
|
|
|
.. code-block:: php
|
|
:caption: Store a string UUID to the uuid column
|
|
:name: database.uuid-bytes-store-example
|
|
|
|
$sth->execute([
|
|
':uuid' => $uuid->getBytes(),
|
|
':notes' => $notes,
|
|
]);
|
|
|
|
Now, when we ``SELECT`` the records from the database, we will need to convert
|
|
the ``notes.uuid`` column to a ramsey/uuid object, so that we are able to use
|
|
it.
|
|
|
|
.. code-block:: php
|
|
:caption: Covert database UUID bytes to UuidInterface instance
|
|
:name: database.uuid-bytes-convert-example
|
|
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
$uuid = Uuid::uuid4();
|
|
|
|
$dbh = new PDO($dsn, $username, $password);
|
|
|
|
$sth = $dbh->prepare('SELECT uuid, notes FROM notes');
|
|
$sth->execute();
|
|
|
|
foreach ($sth->fetchAll() as $record) {
|
|
$uuid = Uuid::fromBytes($record['uuid']);
|
|
|
|
printf(
|
|
"UUID: %s\nNotes: %s\n\n",
|
|
$uuid->toString(),
|
|
$record['notes']
|
|
);
|
|
}
|
|
|
|
We'll also need to query the database using the bytes.
|
|
|
|
.. code-block:: php
|
|
:caption: Look-up the record from the database, using the UUID bytes
|
|
:name: database.uuid-bytes-select-example
|
|
|
|
use Ramsey\Uuid\Uuid;
|
|
|
|
$uuid = Uuid::fromString('278198d3-fa96-4833-abab-82f9e67f4712');
|
|
|
|
$dbh = new PDO($dsn, $username, $password);
|
|
|
|
$sth = $dbh->prepare('
|
|
SELECT uuid, notes
|
|
FROM notes
|
|
WHERE uuid = :uuid
|
|
');
|
|
|
|
$sth->execute([
|
|
':uuid' => $uuid->getBytes(),
|
|
]);
|
|
|
|
$record = $sth->fetch();
|
|
|
|
if ($record) {
|
|
$uuid = Uuid::fromBytes($record['uuid']);
|
|
|
|
printf(
|
|
"UUID: %s\nNotes: %s\n\n",
|
|
$uuid->toString(),
|
|
$record['notes']
|
|
);
|
|
}
|
|
|
|
|
|
.. _database.pk:
|
|
|
|
Using As a Primary Key
|
|
######################
|
|
|
|
In the previous examples, we didn't use the UUID as a primary key, but it's
|
|
logical to use the ``notes.uuid`` field as a primary key. There's nothing wrong
|
|
with this approach, but there are a couple points to consider:
|
|
|
|
* InnoDB stores data in the primary key order
|
|
* All the secondary keys also contain the primary key (in InnoDB)
|
|
|
|
We'll deal with the first point in the section, :ref:`database.order`. For the
|
|
second point, if you are using the string version of the UUID (i.e.,
|
|
``char(36)``), then not only will the primary key be large and take up a lot of
|
|
space, but every secondary key that uses that primary key will also be must
|
|
larger.
|
|
|
|
For this reason, if you choose to use UUIDs as primary keys, it might be worth
|
|
the drawbacks to use UUID bytes (i.e., ``char(16)``) instead of the string
|
|
representation (see :ref:`database.bytes`).
|
|
|
|
.. hint::
|
|
|
|
If not using InnoDB with MySQL or MariaDB, consult your database engine
|
|
documentation to find whether it also has similar properties that will
|
|
factor into your use of UUIDs.
|
|
|
|
|
|
.. _database.uk:
|
|
|
|
Using As a Unique Key
|
|
#####################
|
|
|
|
Instead of :ref:`using UUIDs as a primary key <database.pk>`, you may choose to
|
|
use an ``AUTO_INCREMENT`` column with the ``int unsigned`` data type as a
|
|
primary key, while using a ``char(36)`` for UUIDs and setting a ``UNIQUE KEY``
|
|
on this column. This will aid in lookups, while helping keep your secondary keys
|
|
small.
|
|
|
|
.. code-block:: sql
|
|
:caption: Use auto-incrementing column as primary key, with UUID as unique key
|
|
:name: database.id-auto-increment-uuid-unique-key
|
|
|
|
CREATE TABLE `notes` (
|
|
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
|
`uuid` char(36) NOT NULL,
|
|
`notes` text NOT NULL,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `notes_uuid_uk` (`uuid`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
.. _database.order:
|
|
|
|
Insertion Order and Sorting
|
|
###########################
|
|
|
|
UUIDs are not *monotonically increasing*. Even time-based UUIDs are not. If
|
|
using UUIDs as primary keys, the inserts will be random, and the data will be
|
|
scattered on disk (for InnoDB). Over time, as the database size grows, lookups
|
|
will become slower and slower.
|
|
|
|
.. note::
|
|
|
|
See Percona's "`Storing UUID Values in MySQL`_" post, for more details on
|
|
performance of UUIDs as primary keys.
|
|
|
|
To minimize these problems, two solutions have been devised:
|
|
|
|
1. Timestamp first COMBs
|
|
2. Ordered Time UUIDs
|
|
|
|
:ref:`customize.timestamp-first-comb-codec` explains the first solution and how
|
|
to use ramsey/uuid to implement it, while :ref:`customize.ordered-time-codec`
|
|
explains how to use ramsey/uuid to implement the second solution.
|
|
|
|
.. hint::
|
|
|
|
:ref:`Version 6, ordered-time UUIDs <nonstandard.version6>` are a proposed
|
|
new version of UUID that take the place of ordered time UUIDs.
|
|
|
|
|
|
.. _ramsey/uuid-doctrine: https://github.com/ramsey/uuid-doctrine
|
|
.. _Doctrine field type: https://www.doctrine-project.org/projects/doctrine-dbal/en/2.10/reference/types.html
|
|
.. _MariaDB: https://mariadb.org
|
|
.. _PHP Data Objects (PDO): https://www.php.net/pdo
|
|
.. _Storing UUID Values in MySQL: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/
|
|
.. _Version 6, ordered-time UUIDs: nonstandard.version6
|