Should pivot tables in Laravel use UUIDs or auto-incrementing IDs? - php

In Laravel, pivot tables are used to define many-to-many relationships between two models. When creating a pivot table, one has the option of defining an auto-incrementing id field as the primary key or using a UUID instead.
For example, consider the following pivot table that links a benefits table with a units table:
Schema::create('benefit_unit', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->uuid('benefit_id');
$table->uuid('unit_id');
$table->timestamps();
$table->foreign('benefit_id')->references('id')->on('benefits');
$table->foreign('unit_id')->references('id')->on('units');
});
As you can see, this pivot table uses UUIDs as primary keys instead of auto-incrementing IDs.
My question is: does it make any sense to use UUIDs for pivot tables, or is it better to use auto-incrementing IDs like the default behavior in Laravel? Are there any potential security advantages to using UUIDs for pivot tables, or are there any downsides to using them?

I readed an amazing post about this recently. The conclusion of the article is this:
But based on our experience, 95% of the time, the default choice should ? always be Auto Increment Integer. Why?
Readability, and readability leads simplicity. Number is easy to write, easy to remember and easy to communicate. The primary key is not only used by the system, it's also exposed to the end user (e.g. order #), inspected by the operation engineer, customer suppport etc...
If you want more details about that, this is the post: https://www.bytebase.com/blog/choose-primary-key-uuid-or-auto-increment

Related

Laravel MYSQL Foriegn Key

While designing the database for a laravel software using MYSQL, is assigning foreign keys relevant or does Laravel take care of that "Software side".
In the migration we have something like
Table Example:
$table->unsignedBigInteger('user_id');
should i modify the example table in phpmyadmin and make user_id a foreign key? is there a better way or is this not relevant or necessary?
You should define foreign key constraints in your migration. When using code base you should make all the changes using migrations.
Additionally by defining foreign key you actually build a relation between 2 tables otherwise this relation will be at code level. When relation is built database will restrict to have only values which actually exists in main table. Using foreign key you can also do cascading (on update and delete) at db level.
Reference what are the advantages of defining a foreign key
Why should I use foreign keys in database?
if use Laravel 7 ,you can use this short that is a column name user_id foreign to ID user in the table users :
$table->foreignId('user_id')->nullable()->constrained()->onDelete('cascade');

Using a UUID column vs. and incrementing ID and a separate UUID column in relational databases (Laravel, Eloquent)

I often see two ways of doing this:
1: UUID as ID
Schema::create('orders', function (Blueprint $table) {
$table->uuid('id')->unique();
...
2: UUID and Auto-incrementing ID
Schema::create('orders', function (Blueprint $table) {
$table->bigIncrements('id');
$table->uuid('uuid')->unique();
...
Are there any significant benefits in either method? One point I think could see being a benefit in option is with eager loading. For example:
select * from `order_addresses` where `order_addresses`.`id` in (1, 2, 3, 4, 5)
vs.
select * from `order_addresses` where `order_addresses`.`id` in ('683d3bc7-edd7-4f12-a7eb-831bfc5e90eb','20d3d3f5-2b0d-45e0-9f17-f581317b3f97','907af98b-e433-4e55-a641-3f134ea9039c','7713462c-b8aa-4d11-a576-7d4634595a35','4a27368e-5ebe-43e4-bfaf-8be303a84318','e5e618d9-fd25-4f98-bc70-03bc378c338d','5aa3dd71-a4fc-44ac-a810-2e414372d1ed','9c62bbdc-2555-4239-81fd-365ada304619','a7f22427-b7e7-41c0-bc38-f84306f0bae6','386d8318-3da5-4de1-95d0-f144b53ed76d')
However I am not 100%. Can anyone provide any further arguments and/or validate the above?
UUID are better for n-tier application where each application can create it's own identifier without risk of breaking the "unique" rule.
There is no need to have both and the speed difference between unsigned big integer and UUID is small.
UUID uses more space, that's about it.
A string-based UUID does actually have a performance hit in the case of MySQL (and a few others).
https://www.percona.com/blog/2019/11/22/uuids-are-popular-but-bad-for-performance-lets-discuss/
A common approach within the Laravel community seems to be to use an auto-incrementing big integer for the primary key and then add an indexed UUID along side.
You could also check out of the binary UUID packages that are available which stores the UUID more efficiently within the database.

Should I include auto-incremental id in all related tables?

I have multiple tables in a Laravel app with 1-to-1 relationship such as users , users_settings , user_financial
And some 1-to-many relationships such as users_histories
My questions are:
1. Should I always include incremental id at the first?
for example is the id necessary in the Table #2 below?
Table 1:
id (primary,increments) , name, email, password
Table 2:
id (primary,increments), user_id, something_extra
^ why does every guide include this? // e.g. https://appdividend.com/2017/10/12/laravel-one-to-one-eloquent-relationships/
Can't I just use user_id as primary key and skip the incremental key? because I want to auto insert it on table 2 as soon as data is inserted in table 1.
2. How should I name 1-to-1 and 1-to-many tables in Laravel? `
I searched but didn't find any naming convention for different type of relationships...
Currently I do:
users table with primary key id is the base.
1-to-1: users_settings with foreign key user_id
1-to-many: users_histories foreign_key user_id
many-to-many: users_groups foreign_key user_id
should the first two tables be named settings/setting , histories/history instead? sorry I'm a little confused here.
I actually asked a similar question around 2 days ago. Its up to you but I'd say yes. In my case if I don't auto_increment all my ids in the related tables, data won't be associated with the correct user. However, there is an argument for saying auto_increment columns should not be used in this case, but they are useful for other things. According to some, the relationships might not be as meaningful so it'd be up to you and down to the specifics of you data tables for how meaningful the relationship will be. Regardless, you should research more into the advantages of auto_incrementing all your ids in related tables, as well as possible disadvantages before deciding what you want to do. Either way is fine, but they offer different advantages and disadvantages- which you'll need to compare and what works best for your specific case.
This is a well debated topic about the primary key. IMHO, No, you shouldn't. Every column in database should have a purpose. Following this, for your example, I agree that the auto_increment id is redundant and this is simply because it doesn't have a purpose. The second table is still uniquely describing the user so that the primary key should be the user_id.
Beside the above, there is another principle for me to decide whether I need the auto_increment id: whether I can see a table as an entity. For example, user is clearly an entity, but a relationship is not (in most cases), i.e., composite key can serves the purpose. But when an relationship table is extended to have more attributes and it starts to make sense for it to have an auto_increment id.
I don't have much experience on Laravel, but the naming for a database table should not be dictated by a framework. Comparing history and user_history, what a new DBA or developer expect from the two names without looking its data? user_history describes the table more precisely

How to safely rollback Primary Indexes in MySql Database using Laravel migrations

I was using the Entrust roles and permission library for Laravel and Lumen. Although I had a reason to use it differently from the way it was supposed to be used because of my unique case. I needed to have multiple instances of of a user with the same role differentiated by a certain foreign key.
Lets assume I wanted a user to have same role for different jobs or different roles for different jobs so I added a job_id to the role_users table to help me filter the roles a user has for for a particular job..
This just means a user can be an admin for job1 and an admin for job2.. This posed a problem because Entrust some how made primary keys of both role_id and user_id on the role_users table..
First I didn't think that was possible, plus I don't understand why.. This also means that I couldn't have multiple instances of the same role_id and user_id which i wanted. I did a little research and found out I could drop a primary key using $table->dropPrimary() method.
I did this in my up() method, although the action needs to be replicated in my down method. I couldnt' create a primary key there because if multiple instances already exist it would thrown a fatal exception.
Basically I need a way to drop the primary key on condition that it exists so I don't have to recreate it in the down method.
You don't need to put anything in down() in this case.
My usual rule for putting something in down() is when the up() contains something that will prevent my migration to rollback successfully.
In your case dropping a primary key won't affect the rollback in any way.
If you really need to have this rollback. You could add some script that handles duplicates in your table and apply the primary key again

Laravel multiple tables per migration

I am new to Laravel, so a bit new to this framework's best practices. I am trying to understand the best way to approach creating a database using migrations.
The few examples I found on the web, including the Laravel documentation here and here, seem to refer to migration scripts that handle only one table. I am creating an application with around 10 tables, all interrelated with foreign keys between them, some with many-to-many relationships.
Is the recommended approach to have one migration file per table? If so why? (What are the disadvantages of putting all table creation scripts in one file, if any?)
What about foreign keys and relationships? How does one enforce these relationships, and the order in which migrations are executed such that if table1 references a column in table2, table2 is created before table1?
What about many-to-many relationships? Does the relationship (pivot) table need to be created manually too through a separate migration script? If yes what ensures that it is created after the 2 related tables?
During development of your application I don't think you should care too much having only one table per migration, sometimes it's just easier to have some tables togheter in a single migration, but as soon as your system go to production, you will not be able to keep working like that, because you will only migrate in production and probably never rollback, so your migrations will be really small, sometimes you'll have a migration for a single column creation.
The advantages of putting tables in different migrations is the same of having a thin class, the less information you have in one file, the easier is to manage and make changes on it. So if you put all tables in a single migration, it gets harder to maintain, but that's really up to you.
Foreign keys are a good example of why you should create one migration per table and even per foreign key: every time you rollback a table related to foreign keys, you must first delete all foreign dependencies, that's why Laravel creates a migrates them all in the same order, it helps you never screw a table drop. So, create your tables migrations first, then you create your foreign keys migrations, so when you rollback it will first rollback the constraints and then the tables.
I create foreign keys for a table in the same migration of that table, unless I have too much cross foreign keys. But I always create a foreign key in a separate Schema::table() command, because some databases need you to have the column before attaching the constraint to it:
public function up()
{
Schema::create('statuses', function(Blueprint $table)
{
$table->string('id', 64)->primary();
$table->string('user_id', 64)->index();
$table->text('body');
$table->timestamps();
});
Schema::table('statuses', function(Blueprint $table)
{
$table->foreign('user_id')
->references('id')
->on('users')
->onUpdate('cascade')
->onDelete('cascade');
});
}
About many to many, if you create the table and foreign keys togheter, you should first create the master and then the pivot tables, but if you are creating your foreign keys in separate migrations, first create the tables (order will not matter much, but it's also better to be organized in those cases) and then the migrations for the foreign keys.
During development I do a lot of changes in my tables, so I'm always coming back to them, so this is what I use to do, when I'm altering a migration:
1) php artisan migrate:reset many times
2) Alter migration
3) php artisan migrate
If I'm just creating a new one, usually I won't have any problems, because migrations are usually idepotent.
Your last question was already answered, but I'll say it again: Laravel name the migrations files using timestamps, the way you will never have a migration being ran before another one created before it:
2014_07_16_190821_create_statuses_table
And the name of the migration matter, because this one above will create this class:
CreateStatusesTable
So one thing you must do is to create every migration with a different name, otherwise you will end up with two classes with the same name and, not Laravel, but PHP will complaint about it.

Categories