Skip to content

Commit

Permalink
Merge branch 'consecutive-or-optimize' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
zerocrates committed Nov 30, 2023
2 parents 9ca0c8e + d013400 commit 5526e66
Showing 1 changed file with 49 additions and 23 deletions.
72 changes: 49 additions & 23 deletions application/src/Api/Adapter/AbstractResourceEntityAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
return str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], (string) $string);
};

// See below "Consecutive OR optimization" comment
$previousPropertyId = null;
$previousAlias = null;
$previousPositive = null;

foreach ($query['property'] as $queryRow) {
if (!(is_array($queryRow)
&& array_key_exists('property', $queryRow)
Expand All @@ -271,13 +276,41 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
continue;
}

$valuesAlias = $this->createAlias();
$positive = true;
if (in_array($queryType, ['neq', 'nin', 'nsw', 'new', 'nres', 'nex'])) {
$positive = false;
$queryType = substr($queryType, 1);
}
if (!in_array($queryType, ['eq', 'in', 'sw', 'ew', 'res', 'ex'])) {
continue;
}

// Consecutive OR optimization
//
// When we have a run of query rows that are joined by OR and share
// the same property ID (or lack thereof), we don't actually need a
// separate join to the values table; we can just tack additional OR
// clauses onto the WHERE while using the same join and alias. The
// extra joins are expensive, so doing this improves performance where
// many ORs are used.
//
// Rows using "negative" searches need their own separate join to the
// values table, so they're excluded from this optimization on both
// sides: if either the current or previous row is a negative query,
// the current row does a new join.
if ($previousPropertyId === $propertyId
&& $previousPositive
&& $positive
&& $joiner === 'or'
) {
$valuesAlias = $previousAlias;
$usePrevious = true;
} else {
$valuesAlias = $this->createAlias();
$usePrevious = false;
}

switch ($queryType) {
case 'neq':
$positive = false;
// No break.
case 'eq':
$param = $this->createNamedParameter($qb, $value);
$subqueryAlias = $this->createAlias();
Expand All @@ -293,9 +326,6 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;

case 'nin':
$positive = false;
// No break.
case 'in':
$param = $this->createNamedParameter($qb, '%' . $escapeSqlLike($value) . '%');
$subqueryAlias = $this->createAlias();
Expand All @@ -311,9 +341,6 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;

case 'nsw':
$positive = false;
// No break.
case 'sw':
$param = $this->createNamedParameter($qb, $escapeSqlLike($value) . '%');
$subqueryAlias = $this->createAlias();
Expand All @@ -329,9 +356,6 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;

case 'new':
$positive = false;
// No break.
case 'ew':
$param = $this->createNamedParameter($qb, '%' . $escapeSqlLike($value));
$subqueryAlias = $this->createAlias();
Expand All @@ -347,19 +371,13 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
);
break;

case 'nres':
$positive = false;
// No break.
case 'res':
$predicateExpr = $qb->expr()->eq(
"$valuesAlias.valueResource",
$this->createNamedParameter($qb, $value)
);
break;

case 'nex':
$positive = false;
// No break.
case 'ex':
$predicateExpr = $qb->expr()->isNotNull("$valuesAlias.id");
break;
Expand Down Expand Up @@ -391,10 +409,13 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
$whereClause = $qb->expr()->isNull("$valuesAlias.id");
}

if ($joinConditions) {
$qb->leftJoin($valuesJoin, $valuesAlias, 'WITH', $qb->expr()->andX(...$joinConditions));
} else {
$qb->leftJoin($valuesJoin, $valuesAlias);
// See above "Consecutive OR optimization" comment
if (!$usePrevious) {
if ($joinConditions) {
$qb->leftJoin($valuesJoin, $valuesAlias, 'WITH', $qb->expr()->andX(...$joinConditions));
} else {
$qb->leftJoin($valuesJoin, $valuesAlias);
}
}

if ($where == '') {
Expand All @@ -404,6 +425,11 @@ protected function buildPropertyQuery(QueryBuilder $qb, array $query)
} else {
$where .= " AND $whereClause";
}

// See above "Consecutive OR optimization" comment
$previousPropertyId = $propertyId;
$previousPositive = $positive;
$previousAlias = $valuesAlias;
}

if ($where) {
Expand Down

0 comments on commit 5526e66

Please sign in to comment.