Trick based upon reading Jonathan Reinink’s post on composite indices. This will add a set of composite indices so that you’re polymorphic relationships load significantly faster.
It's Friday, so it's time to give away another free lesson from my upcoming Eloquent Performance Patterns course! 🍻
— Jonathan Reinink (@reinink) May 15, 2020
In this lesson I show how powerful compound indexes can be when ordering by multiple columns. 🔥
💌 Sign up here: https://t.co/hPUuzYtYBA
Sending soon! ⏱ pic.twitter.com/3mLJtNzFTl
We want to take the techniques above and add them to our database. For instance, say we have this setup with Brand and Product. We will make the assumption that you have already added the appropriate keys in the db.
<?php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Brand extends Model {
public function product(): MorphTo
{
return $this->morphTo();
}
}
class Toy extends Model {
public function brand(): MorphOne
{
return $this->morphOne(Brand::class, 'product');
}
}
Running this query will be extremely slow!
select * from `toys` where exists (select * from `brands` where `toys`.`id` = `brands`.`product_id` and `brands`.`product_type` = "toy" and `brands`.`deleted_at` is null)
Now let’s create a new migration where we add the composite keys. This will make our lookups much faster when doing the polymorphic queries.
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AlterBrandsTableAddIndexToProduct extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('brands', function (Blueprint $table) {
$table->index(['product_type', 'product_id'], 'product_index');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('brands', function (Blueprint $table) {
$table->dropIndex('product_index');
});
}
}
Now let’s run that query again…
select * from `toys` where exists (select * from `brands` where `toys`.`id` = `brands`.`product_id` and `brands`.`product_type` = "toy" and `brands`.`deleted_at` is null)
So much faster! Joy!