Slow ofMany relationship in Laravel for MariaDB

Viewed 106

What I've got

I've a base model which looks like this :

Schema::create('prospects', function (Blueprint $table) {
    $table->id();
});


class Prospect extends Model
{
    public function latestStep()
    {
        return $this->hasOne(Step::class)
            ->ofMany([
                'date' => 'max',
                'id'   => 'max',
            ]);
    }
}

And a related one :

Schema::create('steps', function (Blueprint $table) {
    $table->id();
    $table->foreignId('prospect_id')->constrained();
    $table->datetime('date');
});


class Step extends Model
{
}

When I want to retrieve prospects which has a latestStep I go like this :

Prospect::whereHas('latestStep')->limit(10)->get();

The generated database request looks like this :

SELECT *
FROM `prospects`
WHERE EXISTS (
    SELECT *
    FROM `steps`
    INNER JOIN (
        SELECT max(`steps`.`id`) AS `id_aggregate`, `steps`.`prospect_id`
        FROM `steps`
        INNER JOIN (
            SELECT max(`steps`.`date`) AS `date_aggregate`, `steps`.`prospect_id`
            FROM `steps`
            GROUP BY `steps`.`prospect_id`
        ) AS `latestStep`
            ON `latestStep`.`date_aggregate` = `steps`.`date`
            AND `latestStep`.`prospect_id` = `steps`.`prospect_id`
        GROUP BY `steps`.`prospect_id`
    ) AS `latestStep`
        ON `latestStep`.`id_aggregate` = `steps`.`id`
        AND `latestStep`.`prospect_id` = `steps`.`prospect_id`
    WHERE `prospects`.`id` = `steps`.`prospect_id`
)
LIMIT 10

The problem

On MySQL 5.7 it runs under 500ms for 20k prospects and 40k steps.

BUT on MariaDB 10.6 it takes between 2 to 3 seconds. If I increase the limit to 100, it takes about 20 to 30 seconds.

How can I solve this ? I've thought on putting an index there, but I don't really know on which columns.

Here are the EXPLAIN for MySQL EXPLAIN for MySQL

And MariaDB EXPLAIN for MariaDB

Edit 1

I've tried this answer https://stackoverflow.com/a/72121388/3789576 and the timing did not change.

Here is the corresponding EXPLAIN for MariaDB EXPLAIN for MariaDB

1 Answers

I can't wrap my head around the query, but here are some indexes that might help:

steps:  INDEX(prospect_id,  date)
steps:  INDEX(date, prospect_id,  id)
steps:  INDEX(prospect_id, id,  date)

When adding a composite index, DROP index(es) with the same leading columns. That is, when you have both INDEX(a) and INDEX(a,b), toss the former.

Also... When you have LIMIT 10 without ORDER BY, the Optimizer is free to pick any 10 rows. Perhaps you would prefer the "latest" or something?

(PS: Thanks for providing the generated SQL, the Create Table, and the Explains.)

Related