Fallback to table iterator on ORDER BY indexField DESC (#4745)

This commit is contained in:
Emmanuel Keller 2024-09-12 14:29:18 +01:00 committed by GitHub
parent 0444d5e6ce
commit 749a30014f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 200 additions and 35 deletions

View file

@ -409,19 +409,9 @@ impl QueryExecutor {
let index_join = Box::new(IndexJoinThingIterator::new(irf, opt, ix, iterators)?);
Some(ThingIterator::IndexJoin(index_join))
}
IndexOperator::Order(asc) => {
if *asc {
Some(ThingIterator::IndexRange(IndexRangeThingIterator::full_range(
irf,
opt.ns()?,
opt.db()?,
&ix.what,
&ix.name,
)))
} else {
None
}
}
IndexOperator::Order => Some(ThingIterator::IndexRange(
IndexRangeThingIterator::full_range(irf, opt.ns()?, opt.db()?, &ix.what, &ix.name),
)),
_ => None,
})
}
@ -561,19 +551,9 @@ impl QueryExecutor {
let unique_join = Box::new(UniqueJoinThingIterator::new(irf, opt, ix, iterators)?);
Some(ThingIterator::UniqueJoin(unique_join))
}
IndexOperator::Order(asc) => {
if *asc {
Some(ThingIterator::UniqueRange(UniqueRangeThingIterator::full_range(
irf,
opt.ns()?,
opt.db()?,
&ix.what,
&ix.name,
)))
} else {
None
}
}
IndexOperator::Order => Some(ThingIterator::UniqueRange(
UniqueRangeThingIterator::full_range(irf, opt.ns()?, opt.db()?, &ix.what, &ix.name),
)),
_ => None,
})
}

View file

@ -189,7 +189,7 @@ pub(super) enum IndexOperator {
Matches(String, Option<MatchRef>),
Knn(Arc<Vec<Number>>, u32),
Ann(Arc<Vec<Number>>, u32, u32),
Order(bool),
Order,
}
impl IndexOption {
@ -283,9 +283,8 @@ impl IndexOption {
e.insert("operator", op);
e.insert("value", val);
}
IndexOperator::Order(asc) => {
IndexOperator::Order => {
e.insert("operator", Value::from("Order"));
e.insert("ascending", Value::from(*asc));
}
};
Value::from(e)

View file

@ -136,14 +136,14 @@ impl<'a> TreeBuilder<'a> {
async fn eval_order(&mut self) -> Result<(), Error> {
if let Some(o) = self.first_order {
if !o.random {
if !o.random && o.direction {
if let Node::IndexedField(id, irf) = self.resolve_idiom(&o.order).await? {
if let Some(ix_ref) = irf.first().cloned() {
self.index_map.order_limit = Some(IndexOption::new(
ix_ref,
id,
IdiomPosition::None,
IndexOperator::Order(o.direction),
IndexOperator::Order,
));
}
}

View file

@ -2602,7 +2602,6 @@ async fn select_from_standard_index_ascending() -> Result<(), Error> {
{
detail: {
plan: {
ascending: true,
index: 'time',
operator: 'Order'
},
@ -2639,7 +2638,6 @@ async fn select_from_standard_index_ascending() -> Result<(), Error> {
{
detail: {
plan: {
ascending: true,
index: 'time',
operator: 'Order'
},
@ -2709,7 +2707,6 @@ async fn select_from_unique_index_ascending() -> Result<(), Error> {
{
detail: {
plan: {
ascending: true,
index: 'time',
operator: 'Order'
},
@ -2742,7 +2739,6 @@ async fn select_from_unique_index_ascending() -> Result<(), Error> {
{
detail: {
plan: {
ascending: true,
index: 'time',
operator: 'Order'
},
@ -2779,3 +2775,193 @@ async fn select_from_unique_index_ascending() -> Result<(), Error> {
//
Ok(())
}
#[tokio::test]
async fn select_from_standard_index_descending() -> Result<(), Error> {
//
let sql = "
DEFINE INDEX time ON TABLE session COLUMNS time;
CREATE session:1 SET time = d'2024-07-01T01:00:00Z';
CREATE session:2 SET time = d'2024-06-30T23:00:00Z';
CREATE session:3 SET other = 'test';
CREATE session:4 SET time = null;
CREATE session:5 SET time = d'2024-07-01T02:00:00Z';
CREATE session:6 SET time = d'2024-06-30T23:30:00Z';
SELECT * FROM session ORDER BY time DESC LIMIT 4 EXPLAIN;
SELECT * FROM session ORDER BY time DESC LIMIT 4;
SELECT * FROM session ORDER BY time DESC EXPLAIN;
SELECT * FROM session ORDER BY time DESC;
";
let mut t = Test::new(sql).await?;
t.skip_ok(7)?;
//
t.expect_vals(&[
"[
{
detail: {
table: 'session'
},
operation: 'Iterate Table'
},
{
detail: {
type: 'Memory'
},
operation: 'Collector'
}
]",
"[
{
id: session:5,
time: d'2024-07-01T02:00:00Z'
},
{
id: session:1,
time: d'2024-07-01T01:00:00Z'
},
{
id: session:6,
time: d'2024-06-30T23:30:00Z'
},
{
id: session:2,
time: d'2024-06-30T23:00:00Z'
}
]",
"[
{
detail: {
table: 'session'
},
operation: 'Iterate Table'
},
{
detail: {
type: 'Memory'
},
operation: 'Collector'
}
]",
"[
{
id: session:5,
time: d'2024-07-01T02:00:00Z'
},
{
id: session:1,
time: d'2024-07-01T01:00:00Z'
},
{
id: session:6,
time: d'2024-06-30T23:30:00Z'
},
{
id: session:2,
time: d'2024-06-30T23:00:00Z'
},
{
id: session:4,
time: NULL
},
{
id: session:3,
other: 'test'
}
]",
])?;
//
Ok(())
}
#[tokio::test]
async fn select_from_unique_index_descending() -> Result<(), Error> {
//
let sql = "
DEFINE INDEX time ON TABLE session COLUMNS time UNIQUE;
CREATE session:1 SET time = d'2024-07-01T01:00:00Z';
CREATE session:2 SET time = d'2024-06-30T23:00:00Z';
CREATE session:3 SET other = 'test';
CREATE session:4 SET time = null;
CREATE session:5 SET time = d'2024-07-01T02:00:00Z';
CREATE session:6 SET time = d'2024-06-30T23:30:00Z';
SELECT * FROM session ORDER BY time DESC LIMIT 3 EXPLAIN;
SELECT * FROM session ORDER BY time DESC LIMIT 3;
SELECT * FROM session ORDER BY time DESC EXPLAIN;
SELECT * FROM session ORDER BY time DESC;
";
let mut t = Test::new(sql).await?;
t.skip_ok(7)?;
//
t.expect_vals(&[
"[
{
detail: {
table: 'session'
},
operation: 'Iterate Table'
},
{
detail: {
type: 'Memory'
},
operation: 'Collector'
}
]",
"[
{
id: session:5,
time: d'2024-07-01T02:00:00Z'
},
{
id: session:1,
time: d'2024-07-01T01:00:00Z'
},
{
id: session:6,
time: d'2024-06-30T23:30:00Z'
}
]",
"[
{
detail: {
table: 'session'
},
operation: 'Iterate Table'
},
{
detail: {
type: 'Memory'
},
operation: 'Collector'
}
]",
"[
{
id: session:5,
time: d'2024-07-01T02:00:00Z'
},
{
id: session:1,
time: d'2024-07-01T01:00:00Z'
},
{
id: session:6,
time: d'2024-06-30T23:30:00Z'
},
{
id: session:2,
time: d'2024-06-30T23:00:00Z'
},
{
id: session:4,
time: NULL
},
{
id: session:3,
other: 'test'
}
]",
])?;
//
Ok(())
}