Skip to content

Commit 9c8c17d

Browse files
committed
store: Speed queries of type A up by adding a redundant clause
This helps greatly in speeding up one of the problematic queries we see in production, bringing execution time down from 13s to 1.2s. Since the additional query can slow down execution times dramatically when we are looking for a large number of children, we only add the clause for small numbers of children. For now, that number is tuneable but should eventually become a constant
1 parent 9414602 commit 9c8c17d

File tree

1 file changed

+29
-1
lines changed

1 file changed

+29
-1
lines changed

store/postgres/src/relational_queries.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ use diesel::query_dsl::{LoadQuery, RunQueryDsl};
1111
use diesel::result::{Error as DieselError, QueryResult};
1212
use diesel::sql_types::{Array, Binary, Bool, Integer, Jsonb, Range, Text};
1313
use diesel::Connection;
14+
use lazy_static::lazy_static;
1415
use std::collections::{BTreeMap, HashSet};
1516
use std::convert::TryFrom;
17+
use std::env;
1618
use std::iter::FromIterator;
1719
use std::str::FromStr;
1820

@@ -31,6 +33,22 @@ use crate::filter::UnsupportedFilter;
3133
use crate::relational::{Column, ColumnType, IdType, Layout, SqlName, Table, PRIMARY_KEY_COLUMN};
3234
use crate::sql_value::SqlValue;
3335

36+
lazy_static! {
37+
/// Use a variant of the query for child_type_a when we are looking up
38+
/// fewer than this many entities. This variable is only here temporarily
39+
/// until we can settle on the right batch size through experimentation
40+
/// and should then just become an ordinary constant
41+
static ref TYPEA_BATCH_SIZE: usize = {
42+
env::var("TYPEA_BATCH_SIZE")
43+
.ok()
44+
.map(|s| {
45+
usize::from_str(&s)
46+
.unwrap_or_else(|_| panic!("TYPE_BATCH_SIZE must be a number, but is `{}`", s))
47+
})
48+
.unwrap_or(0)
49+
};
50+
}
51+
3452
fn str_as_bytes(id: &str) -> QueryResult<scalar::Bytes> {
3553
scalar::Bytes::from_str(&id).map_err(|e| DieselError::SerializationError(Box::new(e)))
3654
}
@@ -1631,9 +1649,13 @@ impl<'a> FilterWindow<'a> {
16311649
// from unnest({parent_ids}) as p(id),
16321650
// children c
16331651
// where c.{parent_field} @> array[p.id]
1652+
// and c.{parent_field} && {parent_ids}
16341653
// and .. other conditions on c ..
16351654
// limit {parent_ids.len} + 1
1636-
1655+
//
1656+
// The redundant `&&` clause is only added when we have fewer than
1657+
// TYPEA_BATCH_SIZE children and helps Postgres to narrow down the
1658+
// rows it needs to pick from `children` to join with `p(id)`
16371659
out.push_sql("\n/* child_type_a */ from unnest(");
16381660
column.bind_ids(&self.ids, out)?;
16391661
out.push_sql(") as p(id), ");
@@ -1644,6 +1666,12 @@ impl<'a> FilterWindow<'a> {
16441666
out.push_sql(" and c.");
16451667
out.push_identifier(column.name.as_str())?;
16461668
out.push_sql(" @> array[p.id]");
1669+
if self.ids.len() < *TYPEA_BATCH_SIZE {
1670+
out.push_sql(" and c.");
1671+
out.push_identifier(column.name.as_str())?;
1672+
out.push_sql(" && ");
1673+
column.bind_ids(&self.ids, out)?;
1674+
}
16471675
self.and_filter(out.reborrow())?;
16481676
limit.single_limit(self.ids.len(), out);
16491677
Ok(())

0 commit comments

Comments
 (0)