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)?);
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue