Skip to content

Commit

Permalink
Performance improvements for singleton sibling lists
Browse files Browse the repository at this point in the history
Previously all sibling lists would result in the generation of an SQL
UNION ALL for each of the siblings to avoid the generation of a
potentially large cross. However this union adds cost and complexity to
the resulting SQL query and is unnecessary where we can detect that all
but one of the siblings has length at most 1.

This PR detects that condition by looking for Limit(1, ...) and Unique
nodes in the query and avoids the UNION in that case.
  • Loading branch information
milessabin committed Nov 5, 2021
1 parent 5078e8c commit 0f49fce
Showing 1 changed file with 26 additions and 24 deletions.
50 changes: 26 additions & 24 deletions modules/sql/src/main/scala/SqlMapping.scala
Original file line number Diff line number Diff line change
Expand Up @@ -580,38 +580,40 @@ trait SqlMapping[F[_]] extends CirceMapping[F] with SqlModule[F] { self =>

/** Does the result of `query` in `context` contain lists of subobjects? */
def containsNonLeafList(query: Query, context: Context): Boolean = {
query match {

case Select(fieldName, _, child) =>
nonLeafList(context, fieldName) ||
context.forField(fieldName, fieldName).map { fieldContext =>
containsNonLeafList(child, fieldContext)
def loop(query: Query, context: Context, maybe: Boolean): Boolean = {
query match {
case Select(fieldName, _, child) =>
maybe || context.forField(fieldName, fieldName).map { fieldContext =>
loop(child, fieldContext, nonLeafList(context, fieldName))
}.getOrElse(false)

case Group(queries) => queries.exists(q => containsNonLeafList(q, context))
case GroupList(queries) => queries.exists(q => containsNonLeafList(q, context))
case Group(queries) => queries.exists(q => loop(q, context, maybe))
case GroupList(queries) => queries.exists(q => loop(q, context, maybe))

case Filter(_, child) => containsNonLeafList(child, context)
case Unique(child) => containsNonLeafList(child, context)
case Limit(_, child) => containsNonLeafList(child, context)
case OrderBy(_, child) => containsNonLeafList(child, context)
case Filter(_, child) => loop(child, context, maybe)
case Unique(child) => loop(child, context, false)
case Limit(n, child) => loop(child, context, maybe && n > 1)
case OrderBy(_, child) => loop(child, context, maybe)

case Narrow(_, child) => containsNonLeafList(child, context)
case Wrap(_, child) => containsNonLeafList(child, context)
case Rename(_, child) => containsNonLeafList(child, context)
case _: Count => false
case Narrow(_, child) => loop(child, context, maybe)
case Wrap(_, child) => loop(child, context, maybe)
case Rename(_, child) => loop(child, context, maybe)
case _: Count => maybe

case Environment(_, child) => containsNonLeafList(child, context)
case Environment(_, child) => loop(child, context, maybe)

case Query.Component(_, _, _) => false
case _: Introspect => false
case _: Defer => false
case Query.Component(_, _, _) => maybe
case _: Introspect => maybe
case _: Defer => maybe

case _: Skip => false
case _: UntypedNarrow => false
case Skipped => false
case Empty => false
case _: Skip => maybe
case _: UntypedNarrow => maybe
case Skipped => maybe
case Empty => maybe
}
}

loop(query, context, false)
}

/** Return the fully aliased column corresponding to the given unaliased columne `cr` in `context` */
Expand Down

0 comments on commit 0f49fce

Please sign in to comment.