Skip to content

Commit

Permalink
Improve eager loading performance on MySQL
Browse files Browse the repository at this point in the history
  • Loading branch information
staudenmeir committed Nov 7, 2018
1 parent 3ff3110 commit a4405e9
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 3 deletions.
4 changes: 3 additions & 1 deletion src/Illuminate/Database/Eloquent/Relations/HasOneOrMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ public function addConstraints()
*/
public function addEagerConstraints(array $models)
{
$this->query->whereIn(
$whereIn = in_array($this->parent->getKeyType(), ['int', 'integer']) ? 'whereInRaw' : 'whereIn';

$this->query->$whereIn(
$this->foreignKey, $this->getKeys($models, $this->localKey)
);
}
Expand Down
24 changes: 24 additions & 0 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,30 @@ protected function whereInExistingQuery($column, $query, $boolean, $not)
return $this;
}

/**
* Add a "where in raw" clause to the query.
*
* @param string $column
* @param array $values
* @param string $boolean
* @param bool $not
* @return $this
*/
public function whereInRaw($column, array $values, $boolean = 'and', $not = false)
{
$type = $not ? 'NotInRaw' : 'InRaw';

if ($values instanceof Arrayable) {
$values = $values->toArray();
}

$values = array_map('intval', $values);

$this->wheres[] = compact('type', 'column', 'values', 'boolean');

return $this;
}

/**
* Add a "where null" clause to the query.
*
Expand Down
16 changes: 16 additions & 0 deletions src/Illuminate/Database/Query/Grammars/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,22 @@ protected function whereNotInSub(Builder $query, $where)
return $this->wrap($where['column']).' not in ('.$this->compileSelect($where['query']).')';
}

/**
* Compile a "where in raw" clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereInRaw(Builder $query, $where)
{
if (! empty($where['values'])) {
return $this->wrap($where['column']).' in ('.implode(', ', $where['values']).')';
}

return '0 = 1';
}

/**
* Compile a "where null" clause.
*
Expand Down
13 changes: 13 additions & 0 deletions tests/Database/DatabaseEloquentHasManyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,19 @@ public function testRelationIsProperlyInitialized()
public function testEagerConstraintsAreProperlyAdded()
{
$relation = $this->getRelation();
$relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int');
$relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]);
$model1 = new EloquentHasManyModelStub;
$model1->id = 1;
$model2 = new EloquentHasManyModelStub;
$model2->id = 2;
$relation->addEagerConstraints([$model1, $model2]);
}

public function testEagerConstraintsAreProperlyAddedWithStringKey()
{
$relation = $this->getRelation();
$relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string');
$relation->getQuery()->shouldReceive('whereIn')->once()->with('table.foreign_key', [1, 2]);
$model1 = new EloquentHasManyModelStub;
$model1->id = 1;
Expand Down
3 changes: 2 additions & 1 deletion tests/Database/DatabaseEloquentHasOneTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ public function testRelationIsProperlyInitialized()
public function testEagerConstraintsAreProperlyAdded()
{
$relation = $this->getRelation();
$relation->getQuery()->shouldReceive('whereIn')->once()->with('table.foreign_key', [1, 2]);
$relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int');
$relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.foreign_key', [1, 2]);
$model1 = new EloquentHasOneModelStub;
$model1->id = 1;
$model2 = new EloquentHasOneModelStub;
Expand Down
4 changes: 3 additions & 1 deletion tests/Database/DatabaseEloquentMorphTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public function testMorphOneSetsProperConstraints()
public function testMorphOneEagerConstraintsAreProperlyAdded()
{
$relation = $this->getOneRelation();
$relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('string');
$relation->getQuery()->shouldReceive('whereIn')->once()->with('table.morph_id', [1, 2]);
$relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent()));

Expand All @@ -50,7 +51,8 @@ public function testMorphManySetsProperConstraints()
public function testMorphManyEagerConstraintsAreProperlyAdded()
{
$relation = $this->getManyRelation();
$relation->getQuery()->shouldReceive('whereIn')->once()->with('table.morph_id', [1, 2]);
$relation->getParent()->shouldReceive('getKeyType')->once()->andReturn('int');
$relation->getQuery()->shouldReceive('whereInRaw')->once()->with('table.morph_id', [1, 2]);
$relation->getQuery()->shouldReceive('where')->once()->with('table.morph_type', get_class($relation->getParent()));

$model1 = new EloquentMorphResetModelStub;
Expand Down
8 changes: 8 additions & 0 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,14 @@ public function testEmptyWhereNotIns()
$this->assertEquals([0 => 1], $builder->getBindings());
}

public function testWhereInRaw()
{
$builder = $this->getBuilder();
$builder->select('*')->from('users')->whereInRaw('id', ['1a', 2]);
$this->assertEquals('select * from "users" where "id" in (1, 2)', $builder->toSql());
$this->assertEquals([], $builder->getBindings());
}

public function testBasicWhereColumn()
{
$builder = $this->getBuilder();
Expand Down

0 comments on commit a4405e9

Please sign in to comment.