Fallback to table iterator on ORDER BY indexField DESC (#4745)
This commit is contained in:
parent
0444d5e6ce
commit
749a30014f
4 changed files with 200 additions and 35 deletions
|
@ -409,19 +409,9 @@ impl QueryExecutor {
|
||||||
let index_join = Box::new(IndexJoinThingIterator::new(irf, opt, ix, iterators)?);
|
let index_join = Box::new(IndexJoinThingIterator::new(irf, opt, ix, iterators)?);
|
||||||
Some(ThingIterator::IndexJoin(index_join))
|
Some(ThingIterator::IndexJoin(index_join))
|
||||||
}
|
}
|
||||||
IndexOperator::Order(asc) => {
|
IndexOperator::Order => Some(ThingIterator::IndexRange(
|
||||||
if *asc {
|
IndexRangeThingIterator::full_range(irf, opt.ns()?, opt.db()?, &ix.what, &ix.name),
|
||||||
Some(ThingIterator::IndexRange(IndexRangeThingIterator::full_range(
|
)),
|
||||||
irf,
|
|
||||||
opt.ns()?,
|
|
||||||
opt.db()?,
|
|
||||||
&ix.what,
|
|
||||||
&ix.name,
|
|
||||||
)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -561,19 +551,9 @@ impl QueryExecutor {
|
||||||
let unique_join = Box::new(UniqueJoinThingIterator::new(irf, opt, ix, iterators)?);
|
let unique_join = Box::new(UniqueJoinThingIterator::new(irf, opt, ix, iterators)?);
|
||||||
Some(ThingIterator::UniqueJoin(unique_join))
|
Some(ThingIterator::UniqueJoin(unique_join))
|
||||||
}
|
}
|
||||||
IndexOperator::Order(asc) => {
|
IndexOperator::Order => Some(ThingIterator::UniqueRange(
|
||||||
if *asc {
|
UniqueRangeThingIterator::full_range(irf, opt.ns()?, opt.db()?, &ix.what, &ix.name),
|
||||||
Some(ThingIterator::UniqueRange(UniqueRangeThingIterator::full_range(
|
)),
|
||||||
irf,
|
|
||||||
opt.ns()?,
|
|
||||||
opt.db()?,
|
|
||||||
&ix.what,
|
|
||||||
&ix.name,
|
|
||||||
)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,7 +189,7 @@ pub(super) enum IndexOperator {
|
||||||
Matches(String, Option<MatchRef>),
|
Matches(String, Option<MatchRef>),
|
||||||
Knn(Arc<Vec<Number>>, u32),
|
Knn(Arc<Vec<Number>>, u32),
|
||||||
Ann(Arc<Vec<Number>>, u32, u32),
|
Ann(Arc<Vec<Number>>, u32, u32),
|
||||||
Order(bool),
|
Order,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexOption {
|
impl IndexOption {
|
||||||
|
@ -283,9 +283,8 @@ impl IndexOption {
|
||||||
e.insert("operator", op);
|
e.insert("operator", op);
|
||||||
e.insert("value", val);
|
e.insert("value", val);
|
||||||
}
|
}
|
||||||
IndexOperator::Order(asc) => {
|
IndexOperator::Order => {
|
||||||
e.insert("operator", Value::from("Order"));
|
e.insert("operator", Value::from("Order"));
|
||||||
e.insert("ascending", Value::from(*asc));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Value::from(e)
|
Value::from(e)
|
||||||
|
|
|
@ -136,14 +136,14 @@ impl<'a> TreeBuilder<'a> {
|
||||||
|
|
||||||
async fn eval_order(&mut self) -> Result<(), Error> {
|
async fn eval_order(&mut self) -> Result<(), Error> {
|
||||||
if let Some(o) = self.first_order {
|
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 Node::IndexedField(id, irf) = self.resolve_idiom(&o.order).await? {
|
||||||
if let Some(ix_ref) = irf.first().cloned() {
|
if let Some(ix_ref) = irf.first().cloned() {
|
||||||
self.index_map.order_limit = Some(IndexOption::new(
|
self.index_map.order_limit = Some(IndexOption::new(
|
||||||
ix_ref,
|
ix_ref,
|
||||||
id,
|
id,
|
||||||
IdiomPosition::None,
|
IdiomPosition::None,
|
||||||
IndexOperator::Order(o.direction),
|
IndexOperator::Order,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2602,7 +2602,6 @@ async fn select_from_standard_index_ascending() -> Result<(), Error> {
|
||||||
{
|
{
|
||||||
detail: {
|
detail: {
|
||||||
plan: {
|
plan: {
|
||||||
ascending: true,
|
|
||||||
index: 'time',
|
index: 'time',
|
||||||
operator: 'Order'
|
operator: 'Order'
|
||||||
},
|
},
|
||||||
|
@ -2639,7 +2638,6 @@ async fn select_from_standard_index_ascending() -> Result<(), Error> {
|
||||||
{
|
{
|
||||||
detail: {
|
detail: {
|
||||||
plan: {
|
plan: {
|
||||||
ascending: true,
|
|
||||||
index: 'time',
|
index: 'time',
|
||||||
operator: 'Order'
|
operator: 'Order'
|
||||||
},
|
},
|
||||||
|
@ -2709,7 +2707,6 @@ async fn select_from_unique_index_ascending() -> Result<(), Error> {
|
||||||
{
|
{
|
||||||
detail: {
|
detail: {
|
||||||
plan: {
|
plan: {
|
||||||
ascending: true,
|
|
||||||
index: 'time',
|
index: 'time',
|
||||||
operator: 'Order'
|
operator: 'Order'
|
||||||
},
|
},
|
||||||
|
@ -2742,7 +2739,6 @@ async fn select_from_unique_index_ascending() -> Result<(), Error> {
|
||||||
{
|
{
|
||||||
detail: {
|
detail: {
|
||||||
plan: {
|
plan: {
|
||||||
ascending: true,
|
|
||||||
index: 'time',
|
index: 'time',
|
||||||
operator: 'Order'
|
operator: 'Order'
|
||||||
},
|
},
|
||||||
|
@ -2779,3 +2775,193 @@ async fn select_from_unique_index_ascending() -> Result<(), Error> {
|
||||||
//
|
//
|
||||||
Ok(())
|
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(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue